java高併發系列 - 第9天:用戶線程和守護線程

守護線程是一種特殊的線程,在後臺默默地完成一些系統性的服務,好比垃圾回收線程JIT線程都是守護線程。與之對應的是用戶線程,用戶線程能夠理解爲是系統的工做線程,它會完成這個程序須要完成的業務操做。若是用戶線程所有結束了,意味着程序須要完成的業務操做已經結束了,系統能夠退出了。因此當系統只剩下守護進程的時候,java虛擬機會自動退出java

java線程分爲用戶線程和守護線程,線程的daemon屬性爲true表示是守護線程,false表示是用戶線程。微信

下面咱們來看一下守護線程的一些特性。併發

程序只有守護線程時,系統會自動退出

package com.itsoku.chat03;

/**
 * 微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo1 {

    public static class T1 extends Thread {
        public T1(String name) {
            super(name);
        }

        @Override
        public void run() {
            System.out.println(this.getName() + "開始執行," + (this.isDaemon() ? "我是守護線程" : "我是用戶線程"));
            while (true) ;
        }
    }

    public static void main(String[] args) {
        T1 t1 = new T1("子線程1");
        t1.start();
        System.out.println("主線程結束");
    }
}

運行上面代碼,結果以下:異步

能夠看到主線程已經結束了,可是程序沒法退出,緣由:子線程1是用戶線程,內部有個死循環,一直處於運行狀態,沒法結束。分佈式

再看下面的代碼:ide

package com.itsoku.chat03;

/**
 * 微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo2 {

    public static class T1 extends Thread {
        public T1(String name) {
            super(name);
        }

        @Override
        public void run() {
            System.out.println(this.getName() + "開始執行," + (this.isDaemon() ? "我是守護線程" : "我是用戶線程"));
            while (true) ;
        }
    }

    public static void main(String[] args) {
        T1 t1 = new T1("子線程1");
        t1.setDaemon(true);
        t1.start();
        System.out.println("主線程結束");
    }
}

運行結果:高併發

程序能夠正常結束了,代碼中經過t1.setDaemon(true);將t1線程設置爲守護線程,main方法所在的主線程執行完畢以後,程序就退出了。大數據

結論:當程序中全部的用戶線程執行完畢以後,無論守護線程是否結束,系統都會自動退出。this

設置守護線程,須要在start()方法以前進行

package com.itsoku.chat03;

import java.util.concurrent.TimeUnit;

/**
 * 微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo3 {

    public static void main(String[] args) {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        t1.setDaemon(true);
    }
}

t1.setDaemon(true);是在t1的start()方法以後執行的,執行會報異常,運行結果以下:線程

線程daemon的默認值

咱們看一下建立線程源碼,位於Thread類的init()方法中:

Thread parent = currentThread();
this.daemon = parent.isDaemon();

dameon的默認值爲爲父線程的daemon,也就是說,父線程若是爲用戶線程,子線程默認也是用戶現場,父線程若是是守護線程,子線程默認也是守護線程。

示例代碼:

package com.itsoku.chat03;

import java.util.concurrent.TimeUnit;

/**
 * 微信公衆號:路人甲Java,專一於java技術分享(帶你玩轉 爬蟲、分佈式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注!
 */
public class Demo4 {
    public static class T1 extends Thread {
        public T1(String name) {
            super(name);
        }

        @Override
        public void run() {
            System.out.println(this.getName() + ".daemon:" + this.isDaemon());
        }
    }

    public static void main(String[] args) throws InterruptedException {

        System.out.println(Thread.currentThread().getName() + ".daemon:" + Thread.currentThread().isDaemon());

        T1 t1 = new T1("t1");
        t1.start();

        Thread t2 = new Thread() {
            @Override
            public void run() {
                System.out.println(this.getName() + ".daemon:" + this.isDaemon());
                T1 t3 = new T1("t3");
                t3.start();
            }
        };

        t2.setName("t2");
        t2.setDaemon(true);
        t2.start();

        TimeUnit.SECONDS.sleep(2);
    }
}

運行代碼,輸出:

main.daemon:false
t1.daemon:false
t2.daemon:true
t3.daemon:true

t1是由主線程(main方法所在的線程)建立的,main線程是t1的父線程,因此t1.daemon爲false,說明t1是用戶線程。

t2線程調用了setDaemon(true);將其設爲守護線程,t3是由t2建立的,因此t3默認線程類型和t2同樣,t2.daemon爲true。

總結

  1. java中的線程分爲用戶線程守護線程
  2. 程序中的全部的用戶線程結束以後,無論守護線程處於什麼狀態,java虛擬機都會自動退出
  3. 調用線程的實例方法setDaemon()來設置線程是不是守護線程
  4. setDaemon()方法必須在線程的start()方法以前調用,在後面調用會報異常,而且不起效
  5. 線程的daemon默認值和其父線程同樣

java高併發系列交流羣

相關文章
相關標籤/搜索