程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> java的線程機制(二) Thread的生命周期

java的線程機制(二) Thread的生命周期

編輯:關於JAVA

之前講到Thread的創建,那是Thread生命周期的第一步,其後就是通過start()方法來啟動Thread,它會 執行一些內部的管理工作然後調用Thread的run()方法,此時該Thread就是alive(活躍)的,而且我們還可以通 過isAlive()方法來確定該線程是否啟動還是終結。

一旦啟動Thread後,我們就只能執行一個方 法:run(),而run()方法就是負責執行Thread的任務,所以終結Thread的方法很簡單,就是終結run()方法。仔 細查看文檔,我們會發現裡面有一個方法:stop(),似乎可以用來停止Thread,但是這個方法已經被廢除了, 因為它存在著內部的競爭。

我們經常需要一個不斷執行的Thread,然後在某個特定的條件下才會終結 它,方法有很多,但最常用的有設定標記和中斷Thread兩種方式。

我們將之前例子中的Thread改寫一 下:

public class RandomCharacterGenerator extends Thread implements CharacterSource {
    static char[] chars;
    static String charArray = "abcdefghijklmnopqrstuvwxyz0123456789";
    static {
        chars = charArray.toCharArray();
    }
        
    private volatile boolean done = false;
    
    Random random;
    CharacterEventHandler handler;
    
    public RandomCharacterGenerator() {
        random = new Random();
        handler = new CharacterEventHandler();
    }
    
    public int getPauseTime() {
        return (int) (Math.max(1000, 5000 * random.nextDouble()));
    }
    
    @Override
    public void addCharacterListener(CharacterListener cl) {
        handler.addCharacterListener(cl);
    }
    
    @Override
    public void removeCharacterListener(CharacterListener cl) {
        handler.removeCharacterListener(cl);
    }
    
    @Override
    public void nextCharacter() {
        handler.fireNewCharacter(this,
                (int) chars[random.nextInt(chars.length)]);
    }
    
    public void run() {
        while(!done){
            nextCharacter();
            try {
                Thread.sleep(getPauseTime());
            } catch (InterruptedException ie) {
                return;
            }
        }
    }
        
    public void setDone(){
        done = true;
    }
}

現在我們多了一個標記:done,這樣我們就可以在代碼中通過調用setDone()來決定什麼時候停止 該Thread。這裡使用了volatile關鍵字,它主要是為了同步。這點會放在同步這裡講。

設定標記的最大問 題就是我們必須等待標記的狀態,這樣就會造成延遲。當然,這種延遲是無法避免的,但必須想辦法縮短到最 小。於是,中斷Thread這種方法就有它的發揮地方了。

我們可以通過interrupt()方法來中斷Thread, 該方法會造成兩個副作用:

1.它會導致任何的阻塞方法都會拋出InterruptedException,我們必須強 制性的捕獲這個錯誤哪怕我們根本就不需要處理它,這也是java的異常處理機制讓人诟病的一個地方。

2.設定Thread對象內部的標記來指示此Thread已經被中斷了,像是這樣:

public void run

(){
     while(!isInterrupted()){
        ...
      }
}

雖然無法避免延遲,但是延遲已經被縮短了。

無論是采用標記還是中斷的方法,我們之所以無 法消除延遲的原因是我們無法確定是檢查標記先還是調用方法先,這就是所謂的race condition,是線程處理 中永遠無法避免的話題。

Thread不僅可以被終結,還可以暫停,掛起和恢復。

Thread原本有 suspend()方法和resume()方法來執行掛起和恢復,但它們和stop()出於同樣的原因,都被廢除了。

我 們可以通過sleep()方法來掛起Thread,當在指定的時間後,它就會自動恢復。嚴格意義上講,sleep並不等同 於suspend,真正的suspend應該是由一個線程來掛起另一個線程,但是sleep只會影響當前的Thread。要想真 正實現掛起和恢復,我們可以使用等待和通知機制,但這個機制最大的問題就是我們的Thread必須使用該技術 來編寫。

Thread在終結後,如果有可能,我們還需要對它進行善後。即使Thread已經被終結了,但是 其他對象只要還持有它的引用,它們就可以調用該Thread的資源,這也會導致該Thread無法被回收。

但我們有時候還是希望繼續保持該Thread的引用,因為我們想要判別它是否真的已經完成了工作,可以使用 join()方法。join()方法會被阻塞住直到Thread完成它的run()方法,但是這個存在風險:第一次對join()方 法的調用可能會一直被阻塞住很長時間直到Thread真正完成,所以,一般情況下我們還是使用isAlive()方法 來判斷。

由於我們可以通過實現一個Runnable接口來定義我們的任務,所以在判斷所在線程是否已經 中斷的時候,就有一個問題:該任務還沒有綁定到任何線程上。我們可以通過currentThread()方法來獲得當 前Thread的引用,接著調用isInterrupted()來判斷線程是否中斷。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved