主线程与守护线程
- 默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。
- 有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。
Thread有一个setDeamon
方法,将当前线程设置为守护线程,其中daemon
是一个boolean值,通过源码我们发现,他会先通过isAlive
方法判断线程的状态。
- 简单介绍一下
isAlive
方法:判断当前的线程是否处于活动状态。活动状态是指线程已经启动且尚未终止,线程处于正在运行(Running)或就绪(Runnable)的状态,就认为线程是存活的。
如果线程已经运行起来再调用这个方法,会抛出异常,所以setDeamon
一定要写在start
方法前。
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
我们可以通过java进程是否结束判断线程是否全部结束。
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
break;
}
}
log.debug("结束");
}, "t1");
// t1.setDaemon(true);
t1.start();
Thread.sleep(1000);
log.debug("结束");
}
}
/*Output:
16:55:07.072 c.Test15 [main] - 结束
*/
运行上例会发现当主线程结束后,t1线程仍然继续运行,此时java进程也继续运行。
如果此时把t1设置成守护进程
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
break;
}
}
log.debug("结束");
}, "t1");
t1.setDaemon(true);
t1.start();
Thread.sleep(1000);
log.debug("结束");
}
}
/*Output:
17:01:46.975 c.Test15 [main] - 结束
Process finished with exit code 0
*/
t1线程在mian线程结束后也自动结束,此时java进程也会结束。
守护线程应用
- 垃圾回收器线程就是一种守护线程;
- Tomcat 中的 Acceptor 和 Poller 线程都是守护线程,所以 Tomcat 接收到 shutdown 命令后,不会等待它们处理完当前请求。