Java多線程之線程的建立、中斷、狀態與屬性

多進程與多線程的本質區別在於:每一個進程擁有本身的一整套變量,而線程則共享數據。若是須要執行一個比較耗時的任務,應該使用獨立的線程。java

能夠經過實現Runnable接口或繼承Thread類來建立獨立的線程。多線程

1) 實現Ruannable接口測試

class MyRunnable implements Runnable {
    public void run() {
        task code
    }
}
Ruannable r = new MyRuannable();
Thread t = new Thread(r);
t.start();

2) 繼承Threadui

class MyThread extends Thread {
    public void run() {
        task code
    }
}
Thread t = new MyThread();
t.start();

對於Thread類或Runnable對象,啓動新線程調用的是start()方法,直接調用run()方法只會在同一個線程中執行任務。start()會啓動這個線程,引起調用run()方法。start()方法會當即返回,而且新線程並行運行。操作系統

若是有不少任務,爲每一個任務建立一個獨立的線程付出的代價太大,可使用線程池來解決這個問題。線程

中斷線程

當線程的run()方法方法體執行完畢(天然終止)或在方法中出現沒有捕獲的異常時(意外終止),線程將終止。另外,可使用interrupt()方法發送中斷請求強制線程終止。日誌

每一個線程都有boolean標誌的中斷狀態位,想弄清當前線程是否被中斷(中斷狀態位是否被置位),須要當前線程本身判斷。而且,被中斷的線程能夠決定如何響應中斷。若是被中斷線程被阻塞,就沒法檢測中斷狀態,就會產生InterruptedException異常。code

public void run() {
    try {
        do some work
        while(! Thread.currentThread().isInterrupted() && more work to do) {
            do more work
        }
    } catch(InterruptedException e) {
        // thread was interrupted during sleep or wait (in blocked)
    } finally {
        cleanup if required
    }
}

當產生異常時,有兩種處理方式選擇。對象

1) 在catch子句中設置中斷狀態。繼承

catch(InterruptedException e) {
    Thread.currentThread().interrupt();
}

2) 不採用try語句塊捕獲異常,交給調用者處理。

void mySubTask() throws InterruptedException {}

測試當前線程是否被中斷有interrupted()isInterrupted()兩個方法。
interrupted()是一個靜態方法,有反作用,會把中斷狀態位置爲false
isInterrupted()是一個實例方法,無反作用。

線程狀態

線程有6種狀態,能夠調用getState()獲取線程狀態。

  • New:新建立狀態,在可運行前還有些工做要作;

  • Runnable:可運行狀態,可能正在運行也可能沒有運行,是否運行需看操做系統調度;

  • Blocked:被阻塞狀態,不活動,可能因爲請求鎖失敗;

  • Waiting:等待狀態,不活動,等待通知,好比調用Thread.join()方法;

  • Timed Waiting:計時等待狀態,不活動,等待超時或通知,好比調用Thread.sleep(long millis)join(long millis)方法;

  • Terminated:被終止狀態,線程可能因爲天然死亡或意外死亡。

線程屬性

線程優先級

每個線程都有一個優先級,默認繼承父線程。注意,不要將程序功能的正確性依賴於優先級。能夠經過setPriority(int newPriority)方法設置線程優先級,最小優先級MIN_PRIORITY爲1,默認優先級NORM_PRIORITY爲5,最高優先級MAX_PRIORITY爲10。

當操做系統的線程調度器有機會選擇新線程時,會首先選擇擁有較高優先級的線程。調用Thread類的靜態方法yield()可以使當前執行線程處於讓步狀態,若是有可運行的線程優先級大於等於此線程,那麼這些線程將被調度。

守護線程

守護線程的惟一用途是爲其餘線程提供服務,經過調用t.setDaemon(true)將線程轉化爲守護線程。若是隻剩下守護線程,虛擬機就會退出。

注意,守護線程應該永遠不去訪問固有資源,由於這些操做可能會發生中斷。

未捕獲異常處理器

線程的run()方法不能拋出任何被檢測的異常,但可能會拋出不被檢測的異常,致使線程終止。就在線程死亡以前,異常被傳遞到未捕獲異常處理器,進行處理,好比使用日誌API發送異常到日誌文件。

class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {
    void uncaughtException(Thread t, Throwable e) {
        // t - terminated thread without exception catch
        // e - uncaught exception object
        do something like send exception info to log file
    }
}

爲線程設置處理器可經過方法setUncaughtExceptionHandler()或靜態方法setDefaultUncaughtExceptionHandler()完成。若是不設置未捕獲異常處理器,那麼默認處理器爲空。

方法getUncaughtExceptionHandler()用於獲取未捕獲異常處理器,可是有反作用,若是返回值爲空,那麼就會將ThreadGroup對象設置爲處理器。線程組ThreadGroup對象的執行流大體以下:

if(該線程組有父線程組) {
    父線程組的uncaughtException方法被調用
} else {
    if(Thread.getDefaultExceptionHandler()返回非空處理器) {
        調用該處理器
    } else {
        if(Throwable是ThreadDeath的一個實例) {
            // 由過期方法stop產生
            什麼都不作
        } else {
            輸出棧蹤影到標準錯誤流
        }
    }
}
相關文章
相關標籤/搜索