JVM线程初探

本文没啥技术含量,纯粹是个人探索为啥一个简单的java程序也有这么多线程的过程记录。时间宝贵的各位看官老爷可以无视本文了。

问题

工作需要,转战Java。又熟悉又陌生,熟悉是因为大学里接触过,陌生是因为工作中没用过。

比起C/C++,Java给我的感觉是不够“直白”,因为总隔着一层JVM。慢慢来吧~

写个HelloWorld观察下在Linux里跑起来是什么样子的:

public class HelloWorld
{  
    public static void main(String[] args) throws InterruptedException
    { 
        System.out.println("Hello, World!");
        Thread.sleep(600000);
        System.out.println("Goodbye, World!");
        System.exit(0);
    }   
}

编译运行:

wanglong@VM-158-139-debian:~/test/java$ javac HelloWorld.java 
wanglong@VM-158-139-debian:~/test/java$ java HelloWorld       
Hello, World!

ps看看:

wanglong@VM-158-139-debian:~$ ps -ef | grep java
wanglong 27657 21811  0 01:32 pts/0    00:00:01 vim HelloWorld.java
wanglong 28192 23150  0 01:38 pts/3    00:00:00 java HelloWorld
wanglong 28292 22050  0 01:39 pts/1    00:00:00 grep java

嗯,不出所料一个java进程,再看看有几个线程,一个?

wanglong@VM-158-139-debian:~$ ps -T -p 28192
  PID  SPID TTY          TIME CMD
28192 28192 pts/3    00:00:00 java
28192 28193 pts/3    00:00:00 java
28192 28194 pts/3    00:00:00 java
28192 28195 pts/3    00:00:00 java
28192 28196 pts/3    00:00:00 java
28192 28198 pts/3    00:00:00 java
28192 28199 pts/3    00:00:00 java
28192 28200 pts/3    00:00:00 java
28192 28201 pts/3    00:00:00 java
28192 28202 pts/3    00:00:00 java
28192 28203 pts/3    00:00:00 java
28192 28204 pts/3    00:00:00 java

探索

一个简单的HelloWorld为什么有12个线程?

这也就是我觉得Java不够直白的一个点了,打印一个HelloWorld整出这么多线程。猜测是JVM为了完成各种各样的任务创建了很多个线程,但是线程名都叫java看不出用途怎么破?

刚好手头一本《深入理解Java虚拟机》,翻翻看有没有讲到JVM中各线程作用的地方。

看目录貌似没有,然而第4章 虚拟机性能监控与故障处理工具中提到了一个命令jstack,貌似有点用处,试试看:

wanglong@VM-158-139-debian:~$ jstack 28192
2019-03-01 01:44:31
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.201-b09 mixed mode):

"Attach Listener" #8 daemon prio=9 os_prio=0 tid=0x00007f1104001000 nid=0x7055 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f112c0ba800 nid=0x6e2b runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f112c0b7800 nid=0x6e2a waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f112c0b5000 nid=0x6e29 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f112c0b3800 nid=0x6e28 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f112c080800 nid=0x6e27 in Object.wait() [0x00007f1117af9000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000f6388ed0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
        - locked <0x00000000f6388ed0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f112c07e000 nid=0x6e26 in Object.wait() [0x00007f1117bfa000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000f6386bf8> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x00000000f6386bf8> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x00007f112c00a800 nid=0x6e21 waiting on condition [0x00007f1134815000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at HelloWorld.main(HelloWorld.java:6)

"VM Thread" os_prio=0 tid=0x00007f112c074000 nid=0x6e24 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f112c01f800 nid=0x6e22 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f112c021800 nid=0x6e23 runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f112c0bd000 nid=0x6e2c waiting on condition 

JNI global references: 5

wanglong@VM-158-139-debian:~$

出来了,数一数刚好12个,来根据名字猜下用途吧,具体细节再研究:

“Attach Listener” #8

Attach?说起attach想起gdb的attach进程的操作,不过肯定没关系了。

跟线程有关系的一个词是detach(pthread_detach),意思是不关注线程的返回状态,线程终止时系统自动清理。不知道跟这个有没有关系。

“Service Thread” #7

服务线程,不知道是服务什么的。Java的世界里貌似很喜欢service、schedule、listener之类的词。

“C1 CompilerThread1” #6

“C2 CompilerThread0” #5

两个编译线程,将Java的字节码转换成机器指令用的么?Java貌似还会动态优化代码运行的热点的,这貌似是Java HotSpot Virtual Machine名字的来历?这个功能是由这两个线程负责的吗?

“Signal Dispatcher” #4

信号分配,这里的signal跟Linux中的信号是一个概念吗?系统将信号发给JVM,然后JVM再将信号派发给用java写的程序?

“Finalizer” #3

干收尾工作的?具体是哪些工作?还是跟try catch中的final有关的。。

“Reference Handler” #2

引用?跟GC有关么,前几天貌似看到java的GC是mark-sweep。

“main” #1

这个很明显了,应该是HelloWorld的主线程,看堆栈正在sleep,跟代码对的上。照目前看来,java中的线程应该是映射到了Linux操作系统中的线程,但如果线程数量很多的话是不是还是如此呢?存疑。

“VM Thread”

看名字,应该是JVM的主线程吧?不知道具体干些啥。

“GC task thread#0 (ParallelGC)”

“GC task thread#1 (ParallelGC)”

俩负责GC的线程,具体是怎么GC的呢?

“VM Periodic Task Thread”

VM周期性任务线程,VM中都有些什么周期性任务?

总结

解决了一个疑惑,却带来了更多的疑惑,好事情。感觉这些疑惑很多可以从《深入理解Java虚拟机》一书中找到答案,抽时间赶紧看了,Java Newbie!

说点什么

avatar
  订阅  
提醒