java線程基礎知識----java daemon線程


  java線程是一個運用很廣泛的重點知識,我們很有必要了解java的daemon線程.

1.首先我們必須清楚的認識到java的線程分為兩類: 用戶線程和daemon線程

  A.  用戶線程: 用戶線程可以簡單的理解為用戶定義的線程,當然包括main線程(以前我錯誤的認為main線程也是一個daemon線程,但是慢慢的發現原來main線程不是,因為如果我再main線程中創建一個用戶線程,並且打出日志,我們會發現這樣一個問題,main線程運行結束了,但是我們的線程任然在運行).

  B.  daemon線程: daemon線程是為我們創建的用戶線程提供服務的線程,比如說jvm的GC等等,這樣的線程有一個非常明顯的特征: 當用戶線程運行結束的時候,daemon線程將會自動退出.(由此我們可以推出下面關於daemon線程的幾條基本特點)

2. daemon 線程的特點: 

  A.  守護線程創建的過程中需要先調用setDaemon方法進行設置,然后再啟動線程.否則會報出IllegalThreadStateException異常.(個人在想一個問題,為什么不能動態更改線程為daemon線程?有時間一個補上這個內容,現在給出一個猜測: 是因為jvm判斷線程狀態的時候,如果當前只存在一個線程Thread1,如果我們把這個線程動態更改為daemon線程,jvm會認為當前已經不存在用戶線程而退出,稍后將會給出正確結論,抱歉!如果有哪位大牛看到,希望給出指點,謝謝!)

  B.  由於daemon線程的終止條件是當前是否存在用戶線程,所以我們不能指派daemon線程來進行一些業務操作,而只能服務用戶線程.

  C.  daemon線程創建的子線程任然是daemon線程.

3. 針對上面給出的daemon線程的特點,我們進行如下驗證:

  A.  對應上面的A特點:

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Thread2());
        thread1.start();
        thread1.setDaemon(true);
        Thread.sleep(10);
        System.out.println("用戶線程退出");
    }
}
class Thread2 implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("1+1="+(1+1));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
運行結果:
Exception in thread "main" java.lang.IllegalThreadStateException
    at java.lang.Thread.setDaemon(Thread.java:1352)
    at ThreadTest.main(ThreadTest.java:5)
1+1=2

  通過上面的例子我們可以發現,我們並不能動態的更改線程為daemon線程,源碼解釋如下:

java源碼:
    public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }

  我們可以發現,在源碼中如果我們的線程狀態是alive的,我們的程序就會拋出異常.

  B.對應上面的B特點:

  

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Thread2());
        thread1.setDaemon(true);
        thread1.start();
        Thread.sleep(10);
        System.out.println("用戶線程退出");
    }
}
class Thread2 implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("1+1="+(1+1));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

運行結果: 用戶線程退出

  通過上面的例子我們可以看到,我們在daemon線程中進行相關的計算工作,但是我們並沒有獲取計算結果,因為用戶線程main已經運行結束.

  C.對應上面的C特點:

  

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Thread2());
        thread.setDaemon(true);
        thread.start();
        System.out.println("Thread是否時daemon線程"+thread.isDaemon());
        Thread.sleep(100);
        System.out.println("用戶線程退出");
    }
}
class Thread2 implements Runnable{
    @Override
    public void run() {
        Thread1 thread1 = new Thread1();
        thread1.start();
        System.out.println("Thread1是否是daemon線程"+thread1.isDaemon());
    }
}
class Thread1 extends Thread{
    public void run () {
        System.out.println("dosomething");
    }
}
運行結果:
Thread是否時daemon線程true
Thread1是否是daemon線程true
dosomething
用戶線程退出

  源碼解析:

 private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
       ......
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
       ......
    }

  在進行Thread初始化的時候,會獲取父進程的isDaemon來復制子進程的daemon.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM