jvm线程
两个问题什么是守护线程?守护线程与非守护线程有什么区别?其应用场景有哪些?一个简单的Java程序,启动后JVM创建了哪些线程,它们的作用是什么?熟悉上面两个问题的同学可以绕过了,不太熟的同学可以继续往下看,哈哈!守护线程守护线程,又叫Daemon线程,它有以下几个特点:守护线程通常由虚拟机自己使用,比如垃圾收集器的线程;Java程序可以把它任
两个问题
- 什么是守护线程?守护线程与非守护线程有什么区别?其应用场景有哪些?
- 一个简单的Java程序,启动后JVM创建了哪些线程,它们的作用是什么?
熟悉上面两个问题的同学可以绕过了,不太熟的同学可以继续往下看,哈哈!
守护线程
守护线程,又叫Daemon线程,它有以下几个特点:
- 守护线程通常由虚拟机自己使用,比如垃圾收集器的线程;
- Java程序可以把它任何创建的线程标记为守护线程;但必须在线程运行前设置;
- Java初始线程(即开始于main方法的线程)是非守护线程;
- 只要还有任何非守护线程在运行,那么这个Java程序也在运行,即这个JVM实例还存活着;当JVM中的所有非守护线程都终止时,JVM实例将自动退出;
看下面这个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public
class
DaemonTest {
public
static
void
main(String[] args)
throws
InterruptedException,
IOException {
Thread daemon =
new
Thread(
new
DaemonThread());
daemon.setName(
"My Daemon Thread"
);
daemon.setDaemon(
true
);
daemon.start();
for
(
int
i =
0
; i <
10
; i++) {
System.out.println(
"Main thread: "
+ i);
Thread.sleep(
1000
);
}
}
}
class
DaemonThread
implements
Runnable {
private
int
index =
0
;
@Override
public
void
run() {
while
(index <
100
) {
System.out.println(
"========= Daemon thread: "
+ index++);
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
}
|
主线程在创建一个Daemon线程后,循环10次结束;此时JVM中没有任何非Daemon线程,因此JVM将自动退出,其结果是导致创建的Daemon线程没有执行完既定任务就被迫终止了;程序结果如下:
1
2
3
4
5
6
7
8
|
Main thread:
0
========= Daemon thread:
0
========= Daemon thread:
1
Main thread:
1
Main thread:
2
......
Main thread:
9
========= Daemon thread:
10
|
结论:不要将业务逻辑封装在Daemon线程中执行,否则结果会不稳定;
JVM中的线程
上面例子中,虚拟机在启动后,一共创建了多少个线程呢?不用猜,我们通过程序或工具来看;
1、通过程序
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
JVMThreadTest {
public
static
void
main(String[] args) {
Thread[] ts = getAllThread();
for
(Thread t : ts) {
System.out.println(t.getId() +
": "
+ t.getName() +
", Priority: "
+ t.getPriority());
}
}
public
static
Thread[] getAllThread() {
ThreadGroup root = Thread.currentThread().getThreadGroup();
ThreadGroup ttg = root;
while
((ttg = ttg.getParent()) !=
null
) {
root = ttg;
}
Thread[] tlist =
new
Thread[(
int
) (root.activeCount() *
1.2
)];
return
java.util.Arrays.copyOf(tlist, root.enumerate(tlist,
true
));
}
}
|
上面的代码先取得所有的线程,然后依次打印其线程Id、线程名和优先级,结果如下:
1
2
3
4
5
|
2
: Reference Handler, Priority:
10
3
: Finalizer, Priority:
8
4
: Signal Dispatcher, Priority:
9
5
: Attach Listener, Priority:
5
1
: main, Priority:
5
|
2、通过jstack
通过jstack -l pid,可以得到如下栈信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
"My Daemon Thread"
daemon prio=
6
tid=
0x01e82400
nid=
0x1740
waiting on condition
[
0x0414f000
]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at inside.jvm.daemon.DaemonThread.run(DaemonTest.java:
34
)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- None
"Low Memory Detector"
daemon prio=
6
tid=
0x01e50400
nid=
0xc78
runnable [
0x0000000
0
]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C1 CompilerThread0"
daemon prio=
10
tid=
0x01e4dc00
nid=
0x410
waiting on conditio
n [
0x00000000
]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Attach Listener"
daemon prio=
10
tid=
0x01e4a800
nid=
0x109c
waiting on condition
[
0x00000000
]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Signal Dispatcher"
daemon prio=
10
tid=
0x01e47800
nid=
0x9b0
runnable [
0x00000000
]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer"
daemon prio=
8
tid=
0x01e40400
nid=
0x17d0
in Object.wait() [
0x03f6f000
]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <
0x23d51148
> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
- locked <
0x23d51148
> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
Locked ownable synchronizers:
- None
"Reference Handler"
daemon prio=
10
tid=
0x01e3b800
nid=
0x1064
in Object.wait() [
0
x03f1f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <
0x23d51048
> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:
485
)
at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
- locked <
0x23d51048
> (a java.lang.ref.Reference$Lock)
Locked ownable synchronizers:
- None
"main"
prio=
6
tid=
0x014f9400
nid=
0x1154
waiting on condition [
0x001ff000
]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at inside.jvm.daemon.DaemonTest.main(DaemonTest.java:
21
)
Locked ownable synchronizers:
- None
"VM Thread"
prio=
10
tid=
0x01dffc00
nid=
0xab8
runnable
"VM Periodic Task Thread"
prio=
10
tid=
0x01e6f400
nid=
0xcd8
waiting on condition
|
3、通过jconsole
通过JDK自带的JConsole也可以查看JVM中的线程,如下图:
各线程介绍
- main线程
这个不用多解释了,主线程,JVM创建的第一个线程,属于非daemon线程;从jstack的结果可以看出,main线程通过Thread.sleep()而进入TIMED_WAITING状态;
- Reference Handler线程
JVM在创建main线程后就创建Reference Handler线程,其优先级最高,为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题;关于引用,可以参考Java:对象的强、软、弱、虚引用这篇blog;
- Finalizer线程
这个线程也是在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线程来说是一种灾难; - Signal Dispatcher线程
该线程用于处理操作系统发送给的JVM信号;关于JVM信号处理可以参考Revelations on Java signal handling and termination这篇blog;
- My Daemon Thread线程
这个就是在main线程里创建出来的daemon线程;
- Attach Listener线程
这个线程暂时还查不到相关的资料,了解的同学请跟贴回复一下,谢谢!
- Low Memory Detector线程
网上查资料,说这个线程是负责对可使用内存进行检测,如果发现可用内存低,分配新的内存空间;我有两个疑问:
1) 在哪里分配新的内存?
2) 这个线程什么时候被创建的?代码在哪? - C1 CompilerThread0线程
用来调用JITing,实时编译装卸class;
- VM Thread、VM Periodic Task Thread线程
关于上面三个线程,我同样存在以上两个疑问;
更多推荐
所有评论(0)