Java中通常有两种线程:
用户线程和
守护线程(也被称为服务线程)
通过
Thread.setDaemon(false)
设置为
用户线程(默认为用户线程)
通过
Thread.setDaemon(true)
设置为
守护线程
线程属性的设置要在线程启动
之前,否则会报 IllegalThreadStateException
异常
用户线程
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("开始执行:" + Thread.currentThread().getName());
while (true){
}
}, "t1");
thread.start();
System.out.println("主线程结束");
}
运行结果如下:
可以看到主线程已经结束,但程序确无法退出。因为t1
线程是用户线程,里边是一个死循环使线程一直处于运行状态,所以无法结束
守护线程
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("开始执行:" + Thread.currentThread().getName());
while (true){
}
}, "t1");
thread.setDaemon(true);
thread.start();
System.out.println("主线程结束");
}
运行结果如下:
通过thread.setDaemon(true)
设置t1
线程为守护线程,程序随着主线程的结束而结束
结论:当程序中所有的用户线程执行完毕之后,不管守护线程是否结束,系统都会自动退出。
必须要在start()方法之前设置守护线程
源码里也有声明,必须在线程启动之前调用setDaemon
方法。
守护线程是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程都是守护线程。与之对应的是用户线程,用户线程可以理解为是系统的工作线程,它会完成这个程序需要完成的业务操作。如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了。所以当系统只剩下守护进程的时候,Java虚拟机会自动退出。
线程默认的daemon值
首先看一下创建线程源码,Thread类的init()
方法
也就是说线程的daemon
的默认值取决于父线程的daemon
值,当父线程为用户线程,子线程默认是用户线程,当父线程为守护线程时 子线程也为守护线程。
示例代码:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
System.out.println("t1 isDaemon:" + Thread.currentThread().isDaemon());
}, "t1");
thread.start();
System.out.println("主线程 isDaemon:" + Thread.currentThread().isDaemon());
TimeUnit.SECONDS.sleep(2);
}
运行结果:
t1
线程是由main方法所在的线程创建的,主线程是t1
的父线程,主线程为用户线程,所以t1.isDaemon
为false
,两个都为用户线程
示例代码2:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
System.out.println("t1 isDaemon:" + Thread.currentThread().isDaemon());
new Thread(()->{
System.out.println("t2 isDaemon:" + Thread.currentThread().isDaemon());
}, "t2").start();
}, "t1");
thread.setDaemon(true);
thread.start();
System.out.println("主线程 isDaemon:" + Thread.currentThread().isDaemon());
TimeUnit.SECONDS.sleep(2);
}
运行结果:
t1
线程手动设置了为守护线程,t1
线程为t2
线程的父线程,线程是否为守护线程默认取决于父线程的值,也就是说t2
默认线程类型和t1
一样的,都为守护线程。
总结
- java中的线程分为用户线程和守护线程(ps:还有虚拟线程也叫协程)
- 程序中的所有的用户线程结束之后,不管守护线程处于什么状态,java虚拟机都会自动退出
- 调用线程的实例方法
setDaemon()
来设置线程是否是守护线程 -
setDaemon()
方法必须在线程的start()
方法之前调用,在后面调用会报异常,并且不起效 - 线程的
daemon
默认值和其父线程一样。