Java 中的线程分为两类,分别为 daemon 线程(守护线程)和 user 线程(用户线程)。
在 JVM 启动时会调用 main 函数, main 函数所在的线程就是一个用户线程,其实在 JVM 内部同时还启动了好多守护线程,比如垃圾回收线程。
守护线程定义:当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
用户线程定义:某种意义上的主要用户线程,只要有用户线程未执行完毕,JVM 虚拟机不会退出。
main函数所在线程是一个用户线程,我们自己创建的线程也是一个用户线程。即使主线程结束了,其他用户线程还没有结束,Java程序也不会结束。
Java 中的守护线程和 Linux 中的守护进程是有些区别的,Linux 守护进程是系统级别的,当系统退出时,才会终止。
而 Java 中的守护线程是 JVM 级别的,当 JVM 中无任何用户进程时,守护进程销毁,JVM 退出,程序终止。总结来说,Java 守护进程的最主要的特点有:
- 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。
创建方式:将线程转换为守护线程可以通过调用 Thread 对象的 setDaemon (true) 方法来实现。
方案一
方案二
方案一结果
方法二结果
【分析】方法一产生的结果是因为,主线程(用户线程)执行完毕,JVM直接将守护线程销毁了。
【分析】方法二产生结果,是因为主线程等待守护线程执行完毕后才结束。
- public class DaemonTest {
- public static void main(String[] args) throws InterruptedException {
- Thread daemon = new Thread(()->{
- try {
- Thread.sleep(1000);
- int sum = 0;
- for (int i = 0; i < 100; i++) {
- sum += i;
- }
- System.out.println(sum);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- // 设置守护线程
- daemon.setDaemon(true);
- daemon.start();
- // daemon.join();
- System.out.println("主线程结束");
- }
- }
作用:我们以 GC 垃圾回收线程举例,它就是一个经典的守护线程,当我们的程序中不再有任何运行的 Thread, 程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是 JVM 上仅剩的线程时,垃圾回收线程会自动离开。
应用场景: