Java并发编程入门(二十三)守护线程

413 阅读3分钟

banner窄.png

铿然架构  |  作者  /  铿然一叶 这是铿然架构的第 88 篇原创文章

相关阅读:

Java并发编程(一)知识地图
Java并发编程(二)原子性
Java并发编程(三)可见性
Java并发编程(四)有序性
Java并发编程(五)创建线程方式概览
Java并发编程入门(六)synchronized用法
Java并发编程入门(七)轻松理解wait和notify以及使用场景
Java并发编程入门(八)线程生命周期
Java并发编程入门(九)死锁和死锁定位
Java并发编程入门(十)锁优化
Java并发编程入门(十一)限流场景和Spring限流器实现
Java并发编程入门(十二)生产者和消费者模式-代码模板
Java并发编程入门(十三)读写锁和缓存模板
Java并发编程入门(十四)CountDownLatch应用场景
Java并发编程入门(十五)CyclicBarrier应用场景
Java并发编程入门(十六)秒懂线程池差别
Java并发编程入门(十七)一图掌握线程常用类和接口
Java并发编程入门(十九)异步任务调度工具CompleteFeature
Java并发编程入门(二十)常见加锁场景和加锁工具
Java并发编程入门(二十一)volatile关键字
Java并发编程入门(二十二)ThreadLocal变量


1. 守护线程

1.JAVA中的线程分为两类,用户线程和守护线程,默认创建的进程、线程都是用户线程

2.当JVM中存在用户线程时,守护线程不会退出,只有当没有任何用户线程时,守护线程会跟着退出。

3.用户线程创建的守护线程,只要有用户线程存在就不会退出;守护线程创建的子线程,不管子线程是不是守护线程都会随着父线程的退出而退出。

daemon_01.jpg

2. 应用场景

生产者-消费者模式下,生产者和消费者都是线程,当生产者线程已经确定不会再产生新的消费数据而退出时,消费者线程也没有存在的必要,此时消费者线程可以设置为守护线程。

需要注意的是:通常的web应用中,会存在很多用户线程,不可能所有的用户线程都退出,此时设置守护线程没有意义,因为永远无法退出,需要使用额外的机制来退出。

3. Show me code

2.1 代码

import java.util.concurrent.TimeUnit;

public class DaemonThreadDemo {

    private static class ParentThread extends Thread {
        private boolean childDaemon = false;
        public ParentThread(boolean childDaemon) {
            this.childDaemon = childDaemon;
        }
        @Override
        public void run() {
            ChildThread childThread = new ChildThread();
            childThread.setName("daemonChild");
            childThread.setDaemon(childDaemon);
            childThread.start();
            System.out.println(getName() + "run....");
            quietlySleep();
        }
    }

    private static class ChildThread extends Thread {
        @Override
        public void run() {
            while(true) {
                System.out.println(getName() + " child run....");
                quietlySleep();
            }
        }
    }

    private static void quietlySleep() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            // nothing to do
        }
    }

    private static void testDependency(boolean threadADaemon, boolean threadBDaemon) {
        ChildThread childThread1 = new ChildThread();
        childThread1.setName("childThread1 ");
        childThread1.setDaemon(threadADaemon);
        childThread1.start();

        ChildThread childThread2 = new ChildThread();
        childThread2.setName("childThread2 ");
        childThread2.setDaemon(threadBDaemon);
        childThread2.start();
    }

    private static void testCreateChildThread(boolean parentDaemon, boolean childDaemon) {
        ParentThread parentThread = new ParentThread(childDaemon);
        parentThread.setDaemon(parentDaemon);
        parentThread.start();
    }

    public static void main(String[] args) {
        //只要其中一个线程是用户线程,不会退出,导致守护线程也不会退出
//        testDependency(true, false);

        //两个线程都是守护线程,因此只要主进程退出,则都退出
//        testDependency(true, true);

        //父线程是守护线程,不管子线程是否守护线程,都会跟着主线程退出而退出
//        testCreateChildThread(true,true);
//        testCreateChildThread(true,false);

        //父线程为用户线程,子线程是守护线程,跟着主线程退出而退出
//        testCreateChildThread(false,true);

        //父线程为用户线程,子线程为守护线程,不会跟着父线程退出而退出
        testCreateChildThread(false,false);
    }
}

2.2 打印日志

2.2.1 testDependency(true, false);

childThread1  child run....
childThread2  child run....
childThread2  child run....
childThread1  child run....
childThread2  child run....
childThread1  child run....

2.2.2 testDependency(true, true);

childThread1  child run....

2.2.3 testCreateChildThread(true,true);

无日志,立即退出。

2.2.4 testCreateChildThread(true,false);

无日志,立即退出。

2.2.5 testCreateChildThread(false,true);

Thread-0run....
daemonChild child run....
daemonChild child run....

2.2.6 testCreateChildThread(false,false);

Thread-0run....
daemonChild child run....
daemonChild child run....
daemonChild child run....
daemonChild child run....
daemonChild child run....

<--阅过留痕,左边点赞!