1.代码示例:
CodeBlock-1:
1.1 守护线程在main线程中创建
public class DaemonThread {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " is Starting");
Thread t = new Thread() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is Starting");
try {
Thread.sleep(10_00);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is finished.");
}
};
// 设置为守护线程
t.setDaemon(true);
t.start();
try {
Thread.sleep(5_00);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is finished.");
}
}
我们如上在main线程中定义了一个子线程t
,将子线程的run方法写为sleep调用比main方法的sleep调用更久时间,以验证父类线程main的执行完毕并释放对子线程有无影响。
控制台输出:
main is Starting
Thread-0 is Starting
main is finished.
Process finished with exit code 0//此代表所有线程执行完毕,并退出
由控制台可知,子线程中的System.out.println(Thread.currentThread().getName()+" is finished.");
语句并没能够得到执行,这是因为子线程比父线程sleep更久,在子类线程sleep期间,父类线程已执行完毕,子类线程没能再次在CPU中得到权限运行,被JVM关闭了线程。
1.2 在main线程中创建普通线程
CodeBlock-2:
此处将CodeBlock-2代码中的子线程设置为守护线程的代码注释掉。
// 设置为守护线程
// t.setDaemon(true);
控制台输出:
main is Starting
Thread-0 is Starting
main is finished.
Thread-0 is finished.
Process finished with exit code 0 //此代表所有线程执行完毕,并退出
此处子线程中的System.out.println(Thread.currentThread().getName()+" is finished.");
语句得到了执行,虽然子线程比父线程sleep更久,但是此时父类线程的消亡对子线程不产生影响,这样一来,子线程中的上述语句总是能够得到执行。
1.3 线程的非正常退出
我们对于CodeBlock-2中的run语句内最后加上以下代码
while(true){
//donothing
}
在IDE的控制台,我们只能得到以下结果显示:
main is Starting
Thread-0 is Starting
main is finished.
Thread-0 is finished.
并没有显示Process finished with exit code 0
的提示,说明子线程 Thread-0一直在内存中运行,如果使用Jconsole可以看到。我们只能选择Console上的Stop Process 键来结束线程的运行,控制台会最后打上:Process finished with exit code -1
,表面有线程未执行完毕,被强制关闭了。
2. Daemon语法说明:
- 通过setDaemon()方法参数设置为true,将线程变为守护线程,并且此方法要在start()方法之前调用,否则会报异常
- 守护线程随着创建它的父线程的线程销毁而被销毁(如果当前只有Daemon线程在运行,JVM会自动关闭所有线程)
- 守护线程一般作为辅助性程序使用,避免某些非主要功能一直是活动线程,导致JVM不能退出
- 一个例子:比如一个主线程执行A、B端口的通信,主线程还创建一个子线程HealthCheck,来进行两端之间有无心跳(即,通信存在),若不存在告诉主线程,主线程重启或关闭。但是主线程关闭,其创建的子线程可能未关闭,一直在进行心跳检查,这样一来,有线程非正常关闭,主线程关闭了,可能其创建的子线程都无法通过其他方式关闭了,而Daemon则是为了解决这个问题而设计的关键词。
- 注意事项:如果设计为守护线程,父线程运行结束会强制结束子线程,尽管子线程代码并未执行完。但是我们不能将子线程理解为运行在父线程内部的线程, 它们对于CPU去调度,也有一定的竞争关系,而不是一个比另一个有固定的优先级顺序。这个就是案例: DaemonThread 所示,如果不是守护线程,子类线程总是会运行完毕(不管创建其的父线程的运行情况),除非任务在while(true)中运行。
- 在守护线程中新建一个线程, 如果这个新线程不进行setDaemon(true)的设置,那么默认继承父线程的isDaemon(true)
- Daemon对于所有线程不是说都应该创建,父线程消亡时子线程即可消亡一方面易于关闭线程,另一方面,也会造成子线程意外消亡的情况,特别是在强调子线程独立性,必须要执行完毕的情况下,不适合设置为守护线程。