每篇一句
把事情变复杂很简单,把事情变简单很复杂。这需要彻底的深入理解!这就是别人强大的原因, 我在路上,我的进步少不了前人的帮助,更加少不了自己的坚持
在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
一. 用户线程
- 用户线程是指用户自定义创建的线程,主线程停止,用户线程不会停止
- main主线程可以看成一个特殊的用户线程
- 只要有一个用户线程没有结束,那么jvm都不会停止.
二. 守护线程
定义: 守护线程是为其他线程服务的线程,最典型的就是cg垃圾回收器
创建守护线程很简单setDaemon(true);方法就行了
Thread thread = new MyThread();
thread.setDaemon(true);
thread.start();
- 必须注意的是:thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。
- 在Daemon线程中产生的新线程也是守护线程。
三. 守护线程很其他线程的关系
1. 守护线程不影响JVM的停止,JVM退出时,不必关心守护线程是否已结束。
- 在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。如果存在一个非守护线程,jvm是不会关闭的
由于以上关系,我们可以推断出以下结论:
- 守护线程不能持有任何需要关闭的资源,例如打开文件等,因为虚拟机退出时,守护线程没有任何机会来关闭文件,这会导致数据丢失。
2. 那守护线程什么时候关闭呢?
- 当守护线程没有需要服务的线程的时候,会关闭,
- 他和JVM没有关系!!!即使JVM退出了守护线程也可能存在, 这一点在很多博客中都误以为守护线程和JVM一同关闭,这是错误的,如果你有幸看到我的博客,又看了别人的博客,发现不一样,那么我可以肯定的告诉你, 他们的错了!
也不能说其他博客说的一点都不对, 因为大多数情况下, JVM关闭了也就意味着, 没有守护线程需要服务的线程了, 自然也就和JVM一同关闭了. 但是站在学术严禁的角度来说, 错就是错!望周知~
说了这么多,其实也一句话总结: 用户线程会影响jvm的关闭, 而守护线程不会影响jvm的关闭
3. Priority与守护线程的关系
有一种传言为守护线程的优先级要低,然而事实是:
- 优先级与是否为守护线程没有必然的联系
- 新的线程的优先级与创建该线程的线程优先级一致。
- 但是建议将守护线程的优先级降低一些。
验证JVM不等待守护线程就会结束
用一段代码验证一下JVM不等待用户启动的守护线程结束就退出的事实。
private static void testDaemonThread() {
long startTime = System.currentTimeMillis();
Thread daemonThreadSetByUser = new Thread("daemonThreadSetByUser") {
@Override
public void run() {
makeThreadSleep(10 * 1000);
super.run();
System.out.println("daemonThreadSetByUser.time cost=" + (System.currentTimeMillis() - startTime));
}
};
daemonThreadSetByUser.setDaemon(true);
daemonThreadSetByUser.start();
//主线程暂定3秒,确保子线程都启动完成
makeThreadSleep(3 * 1000);
dumpAllThreadsInfo();
System.out.println("MainThread.time cost = " + (System.currentTimeMillis() - startTime));
}
private static void dumpAllThreadsInfo() {
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for(Thread thread: threadSet) {
System.out.println("dumpAllThreadsInfo thread.name=" + thread.getName()
+ ";group=" + thread.getThreadGroup()
+ ";isDaemon=" + thread.isDaemon()
+ ";priority=" + thread.getPriority());
}
}
private static void makeThreadSleep(long durationInMillSeconds) {
try {
Thread.sleep(durationInMillSeconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
输出日志信息:
dumpAllThreadsInfo thread.name=Signal Dispatcher;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=9
dumpAllThreadsInfo thread.name=Attach Listener;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=9
dumpAllThreadsInfo thread.name=Monitor Ctrl-Break;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=true;priority=5
dumpAllThreadsInfo thread.name=Reference Handler;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=10
dumpAllThreadsInfo thread.name=main;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=false;priority=5
dumpAllThreadsInfo thread.name=daemonThreadSetByUser;group=java.lang.ThreadGroup[name=main,maxpri=10];isDaemon=true;priority=5
dumpAllThreadsInfo thread.name=Finalizer;group=java.lang.ThreadGroup[name=system,maxpri=10];isDaemon=true;priority=8
MainThread.time cost = 3006
Process finished with exit code 0
参考资料:
https://www.jb51.net/article/154132.htm
https://www.cnblogs.com/baizhanshi/p/8289202.html
https://segmentfault.com/a/1190000018964390