java 内部工作线程介绍

时间:2021-11-20 16:55:41

Java程序运行的过程中,不但包括开发者启动的主线程和子线程。还包括很多内部线程。了解这些线程,对了解Java工作原理,及复杂环境下debug会有帮助。

 

首先需要查看Java程序的内部线程,我使用以下两种方法查看Java下的线程:

        1.Jconsole——JDK自带的JMX查看管理工具(GUI)。

        2.Linux下使用kill -3 processId ,发送命令3号信号——QUIT。可以得到该进程的线程堆栈及内存占用情况输出。

        3.jstack <pid>——JDK自带的查看堆栈工具。

 

两种方法对比:

       平常写程序用jconsole,是很好的工具。因为Jconsole可以实时查看内存和堆栈情况,而kill则不能。但对于生产情况kill还是有用武之地的。

       但这回, Kill方法输出的比Jconsole要更全,Jconsole使用的是JMX主要用来是查看进程工作情况,会隐藏一些内部的线程。对写程序没什么影响,但这次我们希望得到全部内部线程用来分析,所以Jconsole是不够用的。

 

需要先说明一下,我的这次测试,是在SUN  HotSpot(TM) Client VM (14.0-b16)——JDK6 情况下的线程结果,由于JVM可以根据协议各自厂商自己实现,可能会有出入。

 

好了,我们先看看跑一个HelloWorld需要开启几个线程:
我的kill -3 processID 后的结果是:

 

Java代码   java 内部工作线程介绍
  1. Full thread dump Java HotSpot(TM) Client VM (14.0-b16 mixed mode, sharing):  
  2.   
  3. "Low Memory Detector" daemon prio=10 tid=0x08096400 nid=0x6e5 runnable [0x00000000]  
  4.    java.lang.Thread.State: RUNNABLE  
  5.   
  6. "CompilerThread0" daemon prio=10 tid=0x08093400 nid=0x6e4 waiting on condition [0x00000000]  
  7.    java.lang.Thread.State: RUNNABLE  
  8.   
  9. "Signal Dispatcher" daemon prio=10 tid=0x08091800 nid=0x6e3 waiting on condition [0x00000000]  
  10.    java.lang.Thread.State: RUNNABLE  
  11.   
  12. "Finalizer" daemon prio=10 tid=0x08080400 nid=0x6e2 in Object.wait() [0xb52b2000]  
  13.    java.lang.Thread.State: WAITING (on object monitor)  
  14.         at java.lang.Object.wait(Native Method)  
  15.         - waiting on <0x8b7d0b00> (a java.lang.ref.ReferenceQueue$Lock)  
  16.         at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)  
  17.         - locked <0x8b7d0b00> (a java.lang.ref.ReferenceQueue$Lock)  
  18.         at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)  
  19.         at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)  
  20.   
  21. "Reference Handler" daemon prio=10 tid=0x0807ec00 nid=0x6e1 in Object.wait() [0xb5303000]  
  22.    java.lang.Thread.State: WAITING (on object monitor)  
  23.         at java.lang.Object.wait(Native Method)  
  24.         - waiting on <0x8b7d0a08> (a java.lang.ref.Reference$Lock)  
  25.         at java.lang.Object.wait(Object.java:485)  
  26.         at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)  
  27.         - locked <0x8b7d0a08> (a java.lang.ref.Reference$Lock)  
  28.   
  29. "main" prio=10 tid=0x08059000 nid=0x6df waiting on condition [0xb7577000]  
  30.    java.lang.Thread.State: TIMED_WAITING (sleeping)  
  31.         at java.lang.Thread.sleep(Native Method)  
  32.         at com.test.HelloWorld.main(HelloWorld.java:12)  
  33.   
  34. "VM Thread" prio=10 tid=0x0807d000 nid=0x6e0 runnable  
  35.   
  36. "VM Periodic Task Thread" prio=10 tid=0x080aa000 nid=0x6e6 waiting on condition  
  37.   
  38. JNI global references: 597  
  39.   
  40. Heap  
  41.  def new generation   total 960K, used 200K [0x8b7d00000x8b8d00000x8bcb0000)  
  42.   eden space 896K,  22% used [0x8b7d00000x8b8020680x8b8b0000)  
  43.   from space 64K,   0% used [0x8b8b00000x8b8b00000x8b8c0000)  
  44.   to   space 64K,   0% used [0x8b8c00000x8b8c00000x8b8d0000)  
  45.  tenured generation   total 4096K, used 0K [0x8bcb00000x8c0b00000x8f7d0000)  
  46.    the space 4096K,   0% used [0x8bcb00000x8bcb00000x8bcb02000x8c0b0000)  
  47.  compacting perm gen  total 12288K, used 18K [0x8f7d00000x903d00000x937d0000)  
  48.    the space 12288K,   0% used [0x8f7d00000x8f7d4a300x8f7d4c000x903d0000)  
  49.     ro space 8192K,  74% used [0x937d00000x93dc9cc80x93dc9e000x93fd0000)  
  50.     rw space 12288K,  59% used [0x93fd00000x946e75400x946e76000x94bd0000)  
 

 

为了大家能看清,我特意全拷了上来。需要特意说明的是,我使用的是Sleep方法将进程停住,而不是我通常使用的‘调试’方法。为什么已后进行详细说明。

 

我们能看见HelloWorld实际上创建了如下线程:

"Low Memory Detector" 
"CompilerThread0"
"Signal Dispatcher"
"Finalizer"
"Reference Handler"
"main" 
"VM Thread"
"VM Periodic Task Thread"

 

由于我手头上的资料也不是很全,简单说明一下都是干什么用的。

"Low Memory Detector" 负责对可使用内存进行检测,如果发现可用内存低,分配新的内存空间。

"CompilerThread0" 用来调用JITing,实时编译装卸class。

"Signal Dispatcher" 负责分发内部事件。

"Finalizer" 负责调用Finalizer方法。

"Reference Handler" 负责处理引用。

"main" 是主线程。

"VM Thread", "VM Periodic Task Thread"从名字上看是虚机内部线程。(这两个在Jconsole下看不见)

 

我们还可以看出实际上只有"main","VM Thread","Low Memory Detector" 在工作。

而"Low Memory Detector" ,"CompilerThread0","Signal Dispatcher","Finalizer","Reference Handler"都是daemo进程。

 

之后我用Jconsole查看了一下,发现多了几个线程:

 

Java代码   java 内部工作线程介绍
  1. "RMI TCP Connection(4)-127.0.1.1" daemon prio=10 tid=0x08201000 nid=0x2846 runnable [0xac968000]  
  2.    java.lang.Thread.State: RUNNABLE  
  3.     at java.net.SocketInputStream.socketRead0(Native Method)  
  4.     at java.net.SocketInputStream.read(SocketInputStream.java:129)  
  5.     at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)  
  6.     at java.io.BufferedInputStream.read(BufferedInputStream.java:237)  
  7.     - locked <0xad7543a8> (a java.io.BufferedInputStream)  
  8.     at java.io.FilterInputStream.read(FilterInputStream.java:66)  
  9.     at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:517)  
  10.     at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)  
  11.     at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)  
  12.     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)  
  13.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)  
  14.     at java.lang.Thread.run(Thread.java:619)  
  15.   
  16. "RMI TCP Connection(3)-127.0.1.1" daemon prio=10 tid=0x081edc00 nid=0x2845 runnable [0xac9b9000]  
  17.    java.lang.Thread.State: RUNNABLE  
  18.     at java.net.SocketInputStream.socketRead0(Native Method)  
  19.     at java.net.SocketInputStream.read(SocketInputStream.java:129)  
  20.     at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)  
  21.     at java.io.BufferedInputStream.read(BufferedInputStream.java:237)  
  22.     - locked <0xad7565c0> (a java.io.BufferedInputStream)  
  23.     at java.io.FilterInputStream.read(FilterInputStream.java:66)  
  24.     at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:517)  
  25.     at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)  
  26.     at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)  
  27.     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)  
  28.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)  
  29.     at java.lang.Thread.run(Thread.java:619)  
  30.   
  31. "RMI TCP Connection(idle)" daemon prio=10 tid=0x081e7000 nid=0x2841 waiting on condition [0xaca0a000]  
  32.    java.lang.Thread.State: TIMED_WAITING (parking)  
  33.     at sun.misc.Unsafe.park(Native Method)  
  34.     - parking to wait for  <0xad706d50> (a java.util.concurrent.SynchronousQueue$TransferStack)  
  35.     at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)  
  36.     at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)  
  37.     at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)  
  38.     at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)  
  39.     at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)  
  40.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)  
  41.     at java.lang.Thread.run(Thread.java:619)  
  42.   
  43. "JMX server connection timeout 15" daemon prio=10 tid=0x081d6800 nid=0x2839 in Object.wait() [0xaca5b000]  
  44.    java.lang.Thread.State: TIMED_WAITING (on object monitor)  
  45.     at java.lang.Object.wait(Native Method)  
  46.     - waiting on <0xad7136e8> (a [I)  
  47.     at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:150)  
  48.     - locked <0xad7136e8> (a [I)  
  49.     at java.lang.Thread.run(Thread.java:619)  
  50.   
  51. "RMI Scheduler(0)" daemon prio=10 tid=0x08160c00 nid=0x2838 waiting on condition [0xacaac000]  
  52.    java.lang.Thread.State: TIMED_WAITING (parking)  
  53.     at sun.misc.Unsafe.park(Native Method)  
  54.     - parking to wait for  <0xad6fdf18> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)  
  55.     at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)  
  56.     at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1963)  
  57.     at java.util.concurrent.DelayQueue.take(DelayQueue.java:164)  
  58.     at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:583)  
  59.     at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:576)  
  60.     at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)  
  61.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)  
  62.     at java.lang.Thread.run(Thread.java:619)  
  63.   
  64. "RMI TCP Connection(1)-127.0.1.1" daemon prio=10 tid=0x080fc800 nid=0x2837 in Object.wait() [0xacafd000]  
  65.    java.lang.Thread.State: TIMED_WAITING (on object monitor)  
  66.     at java.lang.Object.wait(Native Method)  
  67.     - waiting on <0xad740780> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)  
  68.     at com.sun.jmx.remote.internal.ArrayNotificationBuffer.fetchNotifications(ArrayNotificationBuffer.java:417)  
  69.     - locked <0xad740780> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)  
  70.     at com.sun.jmx.remote.internal.ArrayNotificationBuffer$ShareBuffer.fetchNotifications(ArrayNotificationBuffer.java:209)  
  71.     at com.sun.jmx.remote.internal.ServerNotifForwarder.fetchNotifs(ServerNotifForwarder.java:258)  
  72.     at javax.management.remote.rmi.RMIConnectionImpl$2.run(RMIConnectionImpl.java:1227)  
  73.     at javax.management.remote.rmi.RMIConnectionImpl$2.run(RMIConnectionImpl.java:1225)  
  74.     at javax.management.remote.rmi.RMIConnectionImpl.fetchNotifications(RMIConnectionImpl.java:1231)  
  75.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
  76.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
  77.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
  78.     at java.lang.reflect.Method.invoke(Method.java:597)  
  79.     at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)  
  80.     at sun.rmi.transport.Transport$1.run(Transport.java:159)  
  81.     at java.security.AccessController.doPrivileged(Native Method)  
  82.     at sun.rmi.transport.Transport.serviceCall(Transport.java:155)  
  83.     at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)  
  84.     at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)  
  85.     at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)  
  86.     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)  
  87.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)  
  88.     at java.lang.Thread.run(Thread.java:619)  
  89.   
  90. "RMI TCP Accept-0" daemon prio=10 tid=0x08107400 nid=0x2835 runnable [0xacb4e000]  
  91.    java.lang.Thread.State: RUNNABLE  
  92.     at java.net.PlainSocketImpl.socketAccept(Native Method)  
  93.     at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:390)  
  94.     - locked <0xad6fe0e8> (a java.net.SocksSocketImpl)  
  95.     at java.net.ServerSocket.implAccept(ServerSocket.java:453)  
  96.     at java.net.ServerSocket.accept(ServerSocket.java:421)  
  97.     at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:34)  
  98.     at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:369)  
  99.     at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:341)  
  100.     at java.lang.Thread.run(Thread.java:619)  
  101.   
  102. "Attach Listener" daemon prio=10 tid=0x080fb000 nid=0x2834 runnable [0x00000000]  
  103.    java.lang.Thread.State: RUNNABLE  
 

我们从名字可以看出来RMI开头的5个是管理RMI的线程。

JMX的是管理JMX线程。

"Attach Listener"现在不明,但也应该跟Jconsole有关。

以上全部是daemon线程。

 

主要都是用来Jconsole管理该进程时使用的。

 

之后,我又尝试用‘断点’,debug模式,停下程序,发现又多出了三个线程(在jconsole下一样看不见)。

Java代码   java 内部工作线程介绍
  1. "JDWP Command Reader" daemon prio=10 tid=0x080cb400 nid=0x2827 runnable [0x00000000]  
  2.    java.lang.Thread.State: RUNNABLE  
  3.   
  4. "JDWP Event Helper Thread" daemon prio=10 tid=0x080c9400 nid=0x2826 runnable [0x00000000]  
  5.    java.lang.Thread.State: RUNNABLE  
  6.   
  7. "JDWP Transport Listener: dt_socket" daemon prio=10 tid=0x080c6c00 nid=0x2823 runnable [0x00000000]  
  8.    java.lang.Thread.State: RUNNABLE  

 

 JDWP是Java Debug Wire Protocol的缩写,是Java Debug使用的一种协议。以上三个线程,应该就是用来Debug时,创建的。以上三个全是daemon线程。

 

由于资料缺少,就先写到这里了,已后有资料了在补...........

 

 

 

参考资料:

http://en.allexperts.com/q/Java-1046/Jvm-threads.htm

http://java.sun.com/j2se/1.5.0/docs/guide/jpda/jdwp-spec.html


转自:

http://java-boy.iteye.com/blog/464953