私の開発者の友達は最近、次の質問をしました。 Linuxシステムでスレッドを含むJavaアプリケーションを実行すると、そのスレッドはデフォルトのLinuxオペレーティングシステムにどのように表示されますか?
それでは、Javaスレッドとは何ですか?
答え1
全長DR
存在するJava 1.1、緑色のスレッドが使用される唯一のスレッドモデルです。Java仮想マシン(JVM),9少なくともソラリス。緑色のスレッドは基本スレッドに比べていくつかの制限があるため、Javaの後続のバージョンでは基本スレッドを優先して緑色のスレッドを削除しました。10、11。
源泉:緑の糸
次の図は、オペレーティングシステムの観点からJavaスレッドを分析する方法を示しています。
背景
この問題の調査中に、次のタイトルの質問と回答が見つかりました。Java JVMはpthreadを使用しますか? 。この質問にはJVMソースコードへのリンクがあります。OpenJDK/jdk8u/jdk8u/ホットスポット。特に、この段落は次のとおりです。
// Serialize thread creation if we are running with fixed stack LinuxThreads
bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
if (lock) {
os::Linux::createThread_lock()->lock_without_safepoint_check();
}
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
pthread_attr_destroy(&attr);
ここでは、JVMが別のpthreadを使用していることがわかります。POSIXスレッド。追加の詳細pthreads(7) マニュアルページ:
POSIX.1は、しばしばPOSIXスレッドまたはPthreadと呼ばれるスレッドプログラミングのためのインタフェース(関数、ヘッダファイル)のセットを指定します。単一のプロセスには複数のスレッドを含めることができ、すべて同じプログラムを実行します。これらのスレッドは同じグローバルメモリ(データとヒープセグメント)を共有しますが、各スレッドには独自のスタック(自動変数)があります。
このため、Javaに存在する唯一のスレッドはLinuxのpthreadです。
はい
実験これをより詳細に証明するために、次の例を使用できます。スカラーアプリ結局のところ、これは単なるJavaアプリケーションです。
アプリケーションはDockerコンテナで実行されますが、それを使用してスレッドを使用している実行中のJavaアプリケーションを調査できます。このアプリケーションを使用するには、Gitリポジトリを複製してDockerコンテナをビルドして実行します。
アプリケーションの構築$ git clone https://github.com/slmingol/jvmthreads.git
$ cd jvmthreads
$ docker build -t threading .
$ docker run -it -v ~/.coursier/cache:/root/.cache/coursier -v ~/.ivy2:/root/.ivy2 -v ~/.sbt:/root/.sbt -v ~/.bintray:/root/.bintray -v $(pwd):/threading threading:latest /bin/bash
この時点で、Dockerコンテナ内にあり、次の種類のプロンプトが表示されます。
root@27c0fa503da6:/threading#
アプリケーションの実行
ここでアプリケーションを実行しようとしていますsbt
。
$ sbt compile compileCpp "runMain com.threading.ThreadingApp"
Ctrlこのアプリケーションが起動し始めたら、アプリケーションで+を使用して研究できます。ZSIGSTP
root@27c0fa503da6:/threading# sbt compile compileCpp "runMain com.threading.ThreadingApp"
[info] Loading settings from metaplugins.sbt ...
[info] Loading project definition from /threading/project/project
[info] Loading settings from plugins.sbt ...
[info] Loading project definition from /threading/project
[info] Loading settings from build.sbt ...
[warn] Missing bintray credentials. Either create a credentials file with the bintrayChangeCredentials task, set the BINTRAY_USER and BINTRAY_PASS environment variables or pass bintray.user and bintray.pass properties to sbt.
[warn] Missing bintray credentials. Either create a credentials file with the bintrayChangeCredentials task, set the BINTRAY_USER and BINTRAY_PASS environment variables or pass bintray.user and bintray.pass properties to sbt.
^Z
[1]+ Stopped sbt compile compileCpp "runMain com.threading.ThreadingApp"
分析アプリケーション
ps
これで、テスト中のアプリケーションがオペレーティングシステムの観点からどのように機能するかを確認するなど、一般的なUNIXツールを使用できます。
標準ps
cmdには、実行中の一般的なアプリケーションのみが表示されます。
root@27c0fa503da6:/threading# ps -eaf
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 02:14 pts/0 00:00:00 /bin/bash
root 1503 1 0 02:37 pts/0 00:00:00 bash /usr/bin/sbt compile compileCpp runMain com.threading.ThreadingApp
root 1571 1503 98 02:37 pts/0 00:00:35 java -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxMetaspaceSize=256m -jar /usr/share/sbt/bin/sbt-launch.jar
root 1707 1571 0 02:37 pts/0 00:00:00 git describe --tags --abbrev=8 --match v[0-9]* --always --dirty=+20191026-0237
root 1718 1 0 02:37 pts/0 00:00:00 ps -eaf
ただし、ps
スレッドビューを使用すると、より完全な画像を見ることができます。
root@27c0fa503da6:/threading# ps -eLf | head -8
UID PID PPID LWP C NLWP STIME TTY TIME CMD
root 1 0 1 0 1 02:14 pts/0 00:00:00 /bin/bash
root 1943 1 1943 0 1 03:08 pts/0 00:00:00 bash /usr/bin/sbt compile compileCpp runMain com.threading.ThreadingApp
root 2011 1943 2011 0 32 03:08 pts/0 00:00:00 java -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxMetaspaceSize=256m -jar /usr/share/sbt/bin/sbt-launch.jar compile compileCpp runMain com.threading.ThreadingApp
root 2011 1943 2012 0 32 03:08 pts/0 00:00:05 java -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxMetaspaceSize=256m -jar /usr/share/sbt/bin/sbt-launch.jar compile compileCpp runMain com.threading.ThreadingApp
root 2011 1943 2013 0 32 03:08 pts/0 00:00:00 java -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxMetaspaceSize=256m -jar /usr/share/sbt/bin/sbt-launch.jar compile compileCpp runMain com.threading.ThreadingApp
root 2011 1943 2014 0 32 03:08 pts/0 00:00:00 java -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxMetaspaceSize=256m -jar /usr/share/sbt/bin/sbt-launch.jar compile compileCpp runMain com.threading.ThreadingApp
root 2011 1943 2015 0 32 03:08 pts/0 00:00:00 java -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxMetaspaceSize=256m -jar /usr/share/sbt/bin/sbt-launch.jar compile compileCpp runMain com.threading.ThreadingApp
メモ:上記では、多くのスレッドがあることがわかります。この例で興味のある列はLWP
およびですNLWP
。
LWP
軽量プロセススレッドを表します。NLWP
LWP 数量を示します。
NLWP 番号は、PID に関連するスレッドの総数を示すため重要です。この例では、対応する数字は 32 です。次のように確認できます。
root@27c0fa503da6:/threading# ps -eLf|grep -E "[3]2.*java" | wc -l
32
ps
次のコマンドを使用して、これらのスレッドを確認する別の方法を取得することもできます。
root@27c0fa503da6:/threading# ps -Lo pid,lwp,pri,nice,start,stat,bsdtime,cmd,comm | head -5
PID LWP PRI NI STARTED STAT TIME CMD COMMAND
1 1 19 0 02:14:42 Ss 0:00 /bin/bash bash
1943 1943 19 0 03:08:41 T 0:00 bash /usr/bin/sbt compile c bash
2011 2011 19 0 03:08:41 Tl 0:00 java -Xms1024m -Xmx1024m -X java
2011 2012 19 0 03:08:41 Tl 0:05 java -Xms1024m -Xmx1024m -X java
注1:l
STAT列のため、この形式はこれがpthreadであることを示しています。
S
- 中断可能な省電力モード(イベントが完了するまで待機)T
- ジョブ制御信号によって停止l
- マルチスレッド(NPTL pthreadと同様にCLONE_THREADを使用)。
ノート2:SIGSTP制御信号+を使用してプロセスが停止したことを示すS
ため、ここで重要です。T
CtrlZ
ps -T
スイッチを使用してスレッドとして処理することもできます。
root@27c0fa503da6:/threading# ps -To pid,tid,tgid,tty,time,comm | head -5
PID TID TGID TT TIME COMMAND
1 1 1 pts/0 00:00:00 bash
1943 1943 1943 pts/0 00:00:00 bash
2011 2011 2011 pts/0 00:00:00 java
2011 2012 2011 pts/0 00:00:05 java
上記のスイッチps
:
-L Show threads, possibly with LWP and NLWP columns.
-T Show threads, possibly with SPID column.
アプリを完全に実行してください。
参考のために質問がある場合は、Scala / Javaアプリケーションの完全な実行を確認してください。
root@27c0fa503da6:/threading# sbt compile compileCpp "runMain com.threading.ThreadingApp"
[info] Loading settings from build.sbt ...
[warn] Missing bintray credentials. Either create a credentials file with the bintrayChangeCredentials task, set the BINTRAY_USER and BINTRAY_PASS environment variables or pass bintray.user and bintray.pass properties to sbt.
[warn] Missing bintray credentials. Either create a credentials file with the bintrayChangeCredentials task, set the BINTRAY_USER and BINTRAY_PASS environment variables or pass bintray.user and bintray.pass properties to sbt.
[info] Set current project to threading (in build file:/threading/)
[info] Executing in batch mode. For better performance use sbt's shell
[warn] Credentials file /root/.bintray/.credentials does not exist, ignoring it
[success] Total time: 2 s, completed Oct 26, 2019 4:11:38 AM
[success] Total time: 1 s, completed Oct 26, 2019 4:11:39 AM
[warn] Credentials file /root/.bintray/.credentials does not exist, ignoring it
[info] Running (fork) com.threading.ThreadingApp
[info] Started a linux thread 140709608359680!
[info] Started a linux thread 140709599966976!
[info] Starting thread_entry_pointStarted a linux thread 140709591574272!
[info] Starting thread_entry_pointStarting thread_entry_pointStarted a linux thread 140709583181568!
[info] Running Thread 1
[info] Starting thread_entry_pointStarted a linux thread 140709369739008!
[info] Running Thread 2
[info] Starting thread_entry_pointStarted a linux thread 140709608359680!
[info] Running Thread 3
[info] Starting thread_entry_pointStarted a linux thread 140709599966976!
[info] Running Thread 4
[info] Running Thread 5Starting thread_entry_pointStarting thread_entry_pointStarted a linux thread 140709361346304!
[info] Running Thread 6
[info] Starting thread_entry_pointStarted a linux thread 140709583181568!
[info] Started a linux thread 140709591574272!
[info] Starting thread_entry_pointStarting thread_entry_pointStarted a linux thread 140709352953600!
[info] Running Thread 7
[info] Running Thread 9
[info] Started a linux thread 140709369739008!
[info] Starting thread_entry_pointStarted a linux thread 140709608359680!
[info] Running Thread 8
[info] Starting thread_entry_pointStarted a linux thread 140709344560896!
[info] Starting thread_entry_pointStarted a linux thread 140709583181568!
[info] Starting thread_entry_pointStarted a linux thread 140709599966976!
[info] Starting thread_entry_pointStarted a linux thread 140709336168192!
[info] Running Thread 10
[info] Running Thread 11
[info] Starting thread_entry_pointStarted a linux thread 140709327775488!
[info] Running Thread 12Started a linux thread 140709591574272!
[info] Running Thread 13
[info] Running Thread 14
[info] Running Thread 16
[info] Running Thread 15
[info] Running Thread 18
[info] Running Thread 17
[info] Running Thread 19
[info] Starting thread_entry_pointStarting thread_entry_point
[success] Total time: 1 s, completed Oct 26, 2019 4:11:40 AM
スレッドダンプ?
一部の人々は、JavaスレッドをLinux LWPとどのように関連付けるかを尋ねます。これを行うには、Javaスレッドダンプを使用して2を比較できます。
Ctrlもう一度上記と同じScalaアプリケーションを使用して+に移動しますZ。
root@52a4b6e78711:/threading# sbt compile compileCpp "runMain com.threading.ThreadingApp"
[info] Loading settings from metaplugins.sbt ...
[info] Loading project definition from /threading/project/project
^Z
[1]+ Stopped sbt compile compileCpp "runMain com.threading.ThreadingApp"
これが完了したら、SIGQUITをJVMに送信する必要があります。これを行うには、通常、次のものを使用できますkill -3 <PID of JVM>
。
root@52a4b6e78711:/threading# ps -eaf
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 12:36 pts/0 00:00:00 /bin/bash
root 7 1 0 12:37 pts/0 00:00:00 bash /usr/bin/sbt compile compileCpp runMain com.threading.ThreadingApp
root 75 7 99 12:37 pts/0 00:00:17 java -Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxMetaspaceSize=256m -jar /usr/share/sbt/bin/sbt-launch.jar
root 130 1 0 12:37 pts/0 00:00:00 ps -eaf
root@52a4b6e78711:/threading# kill -3 75
その後、プログラムの再起動を許可する必要がありますfg
。
root@52a4b6e78711:/threading# fg
sbt compile compileCpp "runMain com.threading.ThreadingApp"
2019-10-26 12:38:00
Full thread dump OpenJDK 64-Bit Server VM (25.181-b13 mixed mode):
"scala-execution-context-global-32" #32 daemon prio=5 os_prio=0 tid=0x00007f87d8002800 nid=0x80 runnable [0x00007f880973d000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c1b08a68> (a scala.concurrent.impl.ExecutionContextImpl$$anon$3)
at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
"scala-execution-context-global-33" #33 daemon prio=5 os_prio=0 tid=0x00007f87dc001000 nid=0x7f runnable [0x00007f880983e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c1b08a68> (a scala.concurrent.impl.ExecutionContextImpl$$anon$3)
at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
"scala-execution-context-global-31" #31 daemon prio=5 os_prio=0 tid=0x00007f87d8001000 nid=0x7e waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"scala-execution-context-global-30" #30 daemon prio=5 os_prio=0 tid=0x00007f87e4003800 nid=0x7d waiting on condition [0x00007f8809a40000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c1b08a68> (a scala.concurrent.impl.ExecutionContextImpl$$anon$3)
at java.util.concurrent.ForkJoinPool.awaitWork(ForkJoinPool.java:1824)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1693)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
メモ:上記のコマンドの部分出力では、kill -3
JVMのスレッドが分析なしでソートされていることがわかります。そのうち32があります。これは、Javaスレッドが実際にLinux LWPと1:1であることを示しています。