Linuxオペレーティングシステムの観点から、Java / JVMはどのタイプのスレッドを使用しますか?

Linuxオペレーティングシステムの観点から、Java / JVMはどのタイプのスレッドを使用しますか?

私の開発者の友達は最近、次の質問をしました。 Linuxシステムでスレッドを含むJavaアプリケーションを実行すると、そのスレッドはデフォルトのLinuxオペレーティングシステムにどのように表示されますか?

それでは、Javaスレッドとは何ですか?

答え1

全長DR

存在するJava 1.1、緑色のスレッドが使用される唯一のスレッドモデルです。Java仮想マシン(JVM),9少なくともソラリス。緑色のスレッドは基本スレッドに比べていくつかの制限があるため、Javaの後続のバージョンでは基本スレッドを優先して緑色のスレッドを削除しました。1011

源泉:緑の糸

次の図は、オペレーティングシステムの観点から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ツールを使用できます。

標準pscmdには、実行中の一般的なアプリケーションのみが表示されます。

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軽量プロセススレッドを表します。
  • NLWPLWP 数量を示します。

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:lSTAT列のため、この形式はこれがpthreadであることを示しています。

  • S- 中断可能な省電力モード(イベントが完了するまで待機)
  • T- ジョブ制御信号によって停止
  • l- マルチスレッド(NPTL pthreadと同様にCLONE_THREADを使用)。

ノート2:SIGSTP制御信号+を使用してプロセスが停止したことを示すSため、ここで重要です。TCtrlZ

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 -3JVMのスレッドが分析なしでソートされていることがわかります。そのうち32があります。これは、Javaスレッドが実際にLinux LWPと1:1であることを示しています。

引用する

関連情報