`
diecui1202
  • 浏览: 96913 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JVM线程知多少

阅读更多

本文已在黄金档上发表,原文链接:http://www.goldendoc.org/2011/11/jvm-thread/

两个问题

  1. 什么是守护线程?守护线程与非守护线程有什么区别?其应用场景有哪些?
  2. 一个简单的Java程序,启动后JVM创建了哪些线程,它们的作用是什么?

熟悉上面两个问题的同学可以绕过了,不太熟的同学可以继续往下看,哈哈!

守护线程

守护线程,又叫Daemon线程,它有以下几个特点:

  1. 守护线程通常由虚拟机自己使用,比如垃圾收集器的线程;
  2. Java程序可以把它任何创建的线程标记为守护线程;但必须在线程运行前设置
  3. Java初始线程(即开始于main方法的线程)是非守护线程;
  4. 只要还有任何非守护线程在运行,那么这个Java程序也在运行,即这个JVM实例还存活着;当JVM中的所有非守护线程都终止时,JVM实例将自动退出;

看下面这个例子:

1 public class DaemonTest {
2  
3     public static void main(String[] args) throws InterruptedException,
4             IOException {
5         Thread daemon = new Thread(new DaemonThread());
6         daemon.setName("My Daemon Thread");
7         daemon.setDaemon(true);
8         daemon.start();
9  
10         for (int i = 0; i < 10; i++) {
11             System.out.println("Main thread: " + i);
12             Thread.sleep(1000);
13         }
14     }
15 }
16  
17 class DaemonThread implements Runnable {
18     private int index = 0;
19  
20     @Override
21     public void run() {
22         while (index < 100) {
23             System.out.println("========= Daemon thread: " + index++);
24             try {
25                 Thread.sleep(1000);
26             catch (InterruptedException e) {
27                 e.printStackTrace();
28             }
29         }
30     }
31 }

主线程在创建一个Daemon线程后,循环10次结束;此时JVM中没有任何非Daemon线程,因此JVM将自动退出,其结果是导致创建的Daemon线程没有执行完既定任务就被迫终止了;程序结果如下:

1 Main thread: 0
2 ========= Daemon thread: 0
3 ========= Daemon thread: 1
4 Main thread: 1
5 Main thread: 2
6 ......
7 Main thread: 9
8 ========= Daemon thread: 10

结论:不要将业务逻辑封装在Daemon线程中执行,否则结果会不稳定;

JVM中的线程

上面例子中,虚拟机在启动后,一共创建了多少个线程呢?不用猜,我们通过程序或工具来看;

1、通过程序

代码如下:

1 public class JVMThreadTest {
2  
3     public static void main(String[] args) {
4         Thread[] ts = getAllThread();
5         for (Thread t : ts) {
6             System.out.println(t.getId() + ": " + t.getName() + ", Priority: "
7                     + t.getPriority());
8         }
9     }
10  
11     public static Thread[] getAllThread() {
12         ThreadGroup root = Thread.currentThread().getThreadGroup();
13         ThreadGroup ttg = root;
14  
15         while ((ttg = ttg.getParent()) != null) {
16             root = ttg;
17         }
18  
19         Thread[] tlist = new Thread[(int) (root.activeCount() * 1.2)];
20         return java.util.Arrays.copyOf(tlist, root.enumerate(tlist, true));
21     }
22 }

上面的代码先取得所有的线程,然后依次打印其线程Id、线程名和优先级,结果如下:

1 2: Reference Handler, Priority: 10
2 3: Finalizer, Priority: 8
3 4: Signal Dispatcher, Priority: 9
4 5: Attach Listener, Priority: 5
5 1: main, Priority: 5

2、通过jstack

通过jstack -l pid,可以得到如下栈信息:

1 "My Daemon Thread" daemon prio=6 tid=0x01e82400 nid=0x1740 waiting on condition
2 [0x0414f000]
3    java.lang.Thread.State: TIMED_WAITING (sleeping)
4         at java.lang.Thread.sleep(Native Method)
5         at inside.jvm.daemon.DaemonThread.run(DaemonTest.java:34)
6         at java.lang.Thread.run(Unknown Source)
7  
8    Locked ownable synchronizers:
9         - None
10  
11 "Low Memory Detector" daemon prio=6 tid=0x01e50400 nid=0xc78 runnable [0x0000000
12 0]
13    java.lang.Thread.State: RUNNABLE
14  
15    Locked ownable synchronizers:
16         - None
17  
18 "C1 CompilerThread0" daemon prio=10 tid=0x01e4dc00 nid=0x410 waiting on conditio
19 n [0x00000000]
20    java.lang.Thread.State: RUNNABLE
21  
22    Locked ownable synchronizers:
23         - None
24  
25 "Attach Listener" daemon prio=10 tid=0x01e4a800 nid=0x109c waiting on condition
26 [0x00000000]
27    java.lang.Thread.State: RUNNABLE
28  
29    Locked ownable synchronizers:
30         - None
31  
32 "Signal Dispatcher" daemon prio=10 tid=0x01e47800 nid=0x9b0 runnable [0x00000000
33 ]
34    java.lang.Thread.State: RUNNABLE
35  
36    Locked ownable synchronizers:
37         - None
38  
39 "Finalizer" daemon prio=8 tid=0x01e40400 nid=0x17d0 in Object.wait() [0x03f6f000
40 ]
41    java.lang.Thread.State: WAITING (on object monitor)
42         at java.lang.Object.wait(Native Method)
43         - waiting on <0x23d51148> (a java.lang.ref.ReferenceQueue$Lock)
44         at java.lang.ref.ReferenceQueue.remove(Unknown Source)
45         - locked <0x23d51148> (a java.lang.ref.ReferenceQueue$Lock)
46         at java.lang.ref.ReferenceQueue.remove(Unknown Source)
47         at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
48  
49    Locked ownable synchronizers:
50         - None
51  
52 "Reference Handler" daemon prio=10 tid=0x01e3b800 nid=0x1064 in Object.wait() [0
53 x03f1f000]
54    java.lang.Thread.State: WAITING (on object monitor)
55         at java.lang.Object.wait(Native Method)
56         - waiting on <0x23d51048> (a java.lang.ref.Reference$Lock)
57         at java.lang.Object.wait(Object.java:485)
58         at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
59         - locked <0x23d51048> (a java.lang.ref.Reference$Lock)
60  
61    Locked ownable synchronizers:
62         - None
63  
64 "main" prio=6 tid=0x014f9400 nid=0x1154 waiting on condition [0x001ff000]
65    java.lang.Thread.State: TIMED_WAITING (sleeping)
66         at java.lang.Thread.sleep(Native Method)
67         at inside.jvm.daemon.DaemonTest.main(DaemonTest.java:21)
68  
69    Locked ownable synchronizers:
70         - None
71  
72 "VM Thread" prio=10 tid=0x01dffc00 nid=0xab8 runnable
73  
74 "VM Periodic Task Thread" prio=10 tid=0x01e6f400 nid=0xcd8 waiting on condition

3、通过jconsole
通过JDK自带的JConsole也可以查看JVM中的线程,如下图:
JVM Threads

各线程介绍

  1. main线程
  2. 这个不用多解释了,主线程,JVM创建的第一个线程,属于非daemon线程;从jstack的结果可以看出,main线程通过Thread.sleep()而进入TIMED_WAITING状态;

  3. Reference Handler线程
  4. JVM在创建main线程后就创建Reference Handler线程,其优先级最高,为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题;关于引用,可以参考Java:对象的强、软、弱、虚引用这篇blog;

  5. Finalizer线程
  6. 这个线程也是在main线程之后创建的,其优先级为8,主要用于在垃圾收集前,调用对象的finalize()方法;关于Finalizer线程的几点:
    1) 只有当开始一轮垃圾收集时,才会开始调用finalize()方法;因此并不是所有对象的finalize()方法都会被执行;
    2) 该线程也是daemon线程,因此如果虚拟机中没有其他非daemon线程,不管该线程有没有执行完finalize()方法,JVM也会退出;
    3) JVM在垃圾收集时会将失去引用的对象包装成Finalizer对象(Reference的实现),并放入ReferenceQueue,由Finalizer线程来处理;最后将该Finalizer对象的引用置为null,由垃圾收集器来回收;
    4) JVM为什么要单独用一个线程来执行finalize()方法呢?如果JVM的垃圾收集线程自己来做,很有可能由于在finalize()方法中误操作导致GC线程停止或不可控,这对GC线程来说是一种灾难;

  7. Signal Dispatcher线程
  8. 该线程用于处理操作系统发送给的JVM信号;关于JVM信号处理可以参考Revelations on Java signal handling and termination这篇blog;

  9. My Daemon Thread线程
  10. 这个就是在main线程里创建出来的daemon线程;

  11. Attach Listener线程
  12. 这个线程暂时还查不到相关的资料,了解的同学请跟贴回复一下,谢谢!

  13. Low Memory Detector线程
  14. 网上查资料,说这个线程是负责对可使用内存进行检测,如果发现可用内存低,分配新的内存空间;我有两个疑问:
    1) 在哪里分配新的内存?
    2) 这个线程什么时候被创建的?代码在哪?

  15. C1 CompilerThread0线程
  16. 用来调用JITing,实时编译装卸class;

  17. VM Thread、VM Periodic Task Thread线程
  18. 关于上面三个线程,我同样存在以上两个疑问;

希望牛人能指点一二,谢谢!

分享到:
评论
1 楼 diecui1202 2012-01-09  
Attach Listener这个应该是HotSpot的动态添加代理的特性搞出来的,是它自有的。可以动态的将一个Agent附加到一个正在运行的JVM上。

具体内容参见http://openjdk.java.net/groups/hotspot/docs/Serviceability.html,在其中搜索“Dynamic Attach”

相关推荐

    JAVA超全面试突击包-答案讲义

    内容包括:Spring、SprngBoot、SpringCloud、Redis、MySQL、MyBatis、JVM、多线程和高并发、设计模式等 Spring框架:包括Spring的核心概念,如依赖注入和面向切面编程 Spring Boot:包括Spring Boot的基础知识,如...

    尚硅谷_互联网大厂高频重点面试题(第2季).xmind

    本期内容包括JUC多线程并发、JVM和GC等目前大厂笔试中会考、面试中会问、工作中会用的高频难点知识。上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、...

    java8集合源码分析-geektime-java-week-training-camp:极客时间-Java每周训练营

    的线程堆栈等数据分析、内存 dump 和内存分析工具; fastThread 相关工具以及面临复杂问题时的几个高级工具的使用; JVM 问题排查分析的常用手段、性能调优的最佳实践经验等; JVM 相关的常见面试问题必知必会、全面...

    java对大数据的处理.pdf

    ⽂件读取:⾸先是⼀个⽂件上传,数据⼊库,10-200万条不等,这⾥主要考虑到⼀次性读取,JVM分配出来的栈内存不⼀定会够(个⼈对 内存这⼀块还是处于⼀知半解的状态,所以⽐较谨慎,若诸位⼤神有好的认知,希望评论...

    总结整理的Android面试Java基础知识点面试资料精编汇总文档资料合集.zip

    JVM面试专题及答案.pdf view面试专题.docx 中高级专题(View+Handler+Binder).docx 初级面试专题(中小厂).docx 多线程专题.docx 多线程面试专题及答案.pdf 大厂高端技术面试专题(有独立项目).docx 常见面试必问...

    Java并发编程的艺术_非扫描

    Java并发编程的艺术_非扫描本书特色本书结合JDK的源码介绍了Java并发框架、线程池的实现原理,帮助读者做到知其所以然。本书对原理的剖析不仅仅局限于Java层面,而是深入到JVM,甚至CPU层面来进行讲解,帮助读者从更...

    Java SE查阅手册.pdf

    笔记旨在理解Java SE的知识,并构建一个比较系统化的知识结构,而不是停在知其然,而不知其所以然的处境以及方便复习和查阅。在笔记中有很小一部分JVM原理的知识,即反译查看Java的字节码。这对我们理解Java SE的...

    JAVA面试题解-刷题文档

    包含JAVA基础、Spring、SpringBoot、JVM、Mybatis、redis、多线程、设计模式、ES等面试答案

    javaee笔试题-JavaExercise:Java学习的代码,包括设计模式、se、ee以及相关测试代码

    java ee笔试题 JavaExercise 方便同步 Arch 与 Windows 主要是一些练习代码... 秋招 算法 LeetCode HDU 剑指 Offer 项目 新人邀请 粉丝节 基础 Java 计算机网络 操作系统 数据结构 ...线程 ...必知必会 ...JVM

    bucket4j:基于令牌泄漏桶算法的Java限速库

    在公知算法的思想上实现,这些思想是事实上的标准,用于IT行业中的速率限制。 有效的无锁实现,Bucket4j在多线程情况下具有良好的可伸缩性。 绝对不妥协的精度,Bucket4j不能使用浮点数或双精度数进行运算,所有...

    Spring.3.x企业应用开发实战(完整版).part2

    经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用Spring的各项功能的同时,还能透彻理解Spring的内部实现,真正做到知其然知其所以然。...

    Spring3.x企业应用开发实战(完整版) part1

    经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练使用Spring的各项功能的同时,还能透彻理解Spring的内部实现,真正做到知其然知其所以然。...

    Guava 16.0 API (CHM格式)

    集合类:集合类库是 Guava 对 JDK 集合类的扩展, 这是 Guava 项目最完善和为人所知的部分。  1. Immutable collections(不变的集合): 防御性编程, 不可修改的集合,并且提高了效率。  2. New collection ...

Global site tag (gtag.js) - Google Analytics