守护线程是什么?

Java线程分为用户线程和守护线程。

  • 守护线程是程序运行的时候在后台提供一种通用服务的线程。所有用户线程停止,进程会停掉所有守护线程,退出程序。
  • Java中把线程设置为守护线程的方法:在 start 线程之前调用线程的 setDaemon(true) 方法。

注意:

  • setDaemon(true) 必须在 start() 之前设置,否则会抛出IllegalThreadStateException异常,该线程仍默认为用户线程,继续执行
  • 守护线程创建的线程也是守护线程
  • 守护线程不应该访问、写入持久化资源,如文件、数据库,因为它会在任何时间被停止,导致资源未释放、数据写入中断等问题
package constxiong.concurrency.a008;

/**
 * 测试守护线程
 * @author yiidian
 * @date 2019-09-03 12:15:59
 */
public class TestDaemonThread {

    public static void main(String[] args) {
        testDaemonThread();
    }
    
    //
    public static void testDaemonThread() {
        Thread t = new Thread(() -> {
            //创建线程,校验守护线程内创建线程是否为守护线程
            Thread t2 = new Thread(() -> {
                System.out.println("t2 : " + (Thread.currentThread().isDaemon() ? "守护线程" : "非守护线程"));
            });
            t2.start();
            
            //当所有用户线程执行完,守护线程会被直接杀掉,程序停止运行
            int i = 1;
            while(true) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t : " + (Thread.currentThread().isDaemon() ? "守护线程" : "非守护线程") + " , 执行次数 : " + i);
                if (i++ >= 10) {
                    break;
                }
            }
        });
        //setDaemon(true) 必须在 start() 之前设置,否则会抛出IllegalThreadStateException异常,该线程仍默认为用户线程,继续执行
        t.setDaemon(true);
        t.start();
        
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //主线程结束
        System.out.println("主线程结束");
    }

}

执行结果

t2 : 守护线程
t : 守护线程 , 执行次数 : 1
主线程结束
t : 守护线程 , 执行次数 : 2

结论:

  • 上述代码线程t,未打印到 t : daemon thread , time : 10,说明所有用户线程停止,进程会停掉所有守护线程,退出程序
  • 当 t.start(); 放到 t.setDaemon(true);  之前,程序抛出IllegalThreadStateException,t 仍然是用户线程,打印如下
Exception in thread "main" t2 : 非守护线程
java.lang.IllegalThreadStateException
    at java.lang.Thread.setDaemon(Thread.java:1359)
    at constxiong.concurrency.a008.TestDaemonThread.testDaemonThread(TestDaemonThread.java:39)
    at constxiong.concurrency.a008.TestDaemonThread.main(TestDaemonThread.java:11)
t : 非守护线程 , 执行次数 : 1
t : 非守护线程 , 执行次数 : 2
t : 非守护线程 , 执行次数 : 3
t : 非守护线程 , 执行次数 : 4
t : 非守护线程 , 执行次数 : 5
t : 非守护线程 , 执行次数 : 6
t : 非守护线程 , 执行次数 : 7
t : 非守护线程 , 执行次数 : 8
t : 非守护线程 , 执行次数 : 9
t : 非守护线程 , 执行次数 : 10