1. 程式人生 > 實用技巧 >JavaSE 多執行緒(一)

JavaSE 多執行緒(一)

1. 執行緒和多執行緒

1.1 執行緒的概念

提到執行緒,首先要從 “程序” 開始講起。對於一般程式而言,其結構大部分都可以劃分為一個入口、一個出口和一個順次執行的語句序列。在程式投入執行時,系統從程式入口開始按語句的順序(其中包括順序、分支和迴圈)完成相應指令直至結尾,從出口退出,同時整個程式結束。這樣的語句結構稱為程序,它是程式的一次動態執行,對應了從程式碼載入、執行至執行完畢的一個完整過程;或者說,程序就是程式在處理機中的一次執行。需要特別明確的是,在這樣的一個結構中,不僅包括了程式程式碼,同時也包括了系統資源的概念。也就是說,一個程序既包括其所要執行的指令,也包括了執行指令所需的任何系統資源,如CPU、記憶體空間、I/O埠等,不同程序所佔用的系統資源相對獨立。

執行緒 是程序執行過程中產生的多條執行線索,是比程序單位更小的執行單位,在形式上同進程十分相似————都是用一個順序執行的語句序列來完成特定的功能。不同的是,它沒有入口,也沒有出口,因此其自身不能自動執行,而必須棲身於某一程序之中,由程序觸發執行。而且在系統資源的使用上,屬於同一程序的所有執行緒共享該程序的系統資源,但是執行緒之間切換的速度比程序切換要快得多。

Java 類庫中的類 java.lang.Thread 允許建立這樣的執行緒,並可控制所建立的執行緒。

1.2 執行緒的結構

在 Java 中,執行緒可以認為是由三部分組成的:

  • 虛擬 CPU,封裝在 java.lang.Thread 類中,它控制著整個執行緒的執行。

  • 執行的程式碼,傳遞給 Thread 類,由 Thread 類控制順序執行。

  • 處理的資料,傳遞給 Thread 類,是在程式碼執行過程中所要處理的資料。

在 Java 中,虛擬 CPU 體現於 Thread 類中。當一個執行緒被構造時,它由構造方法引數、執行程式碼、操作資料來初始化。應該特別注意的時,這三方面是各自獨立的。一個執行緒所執行的程式碼與其他執行緒可以相同,也可以不同;一個執行緒訪問的資料與其他執行緒可以相同,也可以不同。

多執行緒的優勢體現在以下幾個方面:

  • 多執行緒程式設計簡單,效率高。使用多執行緒可以線上程間直接共享資料和資源,而多執行緒之間不能做到這一點。

  • 適合於開發服務程式,如 Web 服務、聊天服務等。

  • 適合於開發有多種互動介面的程式,如聊天程式的客戶端、網路下載工具。

  • 適合於有人機互動又有計算量的程式,如字處理程式Word、Excel等。

2. 執行緒的狀態

Java 的執行緒是通過 Java 軟體包 java.lang 中定義的類 Thread 來實現的。當生成一個 Thread 類的物件之後,是產生了一個執行緒。通過該物件例項,可以啟動執行緒、終止執行緒,或者暫時掛起執行緒等。

Thread 類本身只是執行緒的虛擬 CPU,執行緒所執行的程式碼(或者說執行緒所要完成的工作)是通過方法 run()(包含在一個特定的物件中)完成的,方法 run() 稱為執行緒體。實現執行緒體的特定物件是在初始化執行緒時傳遞給執行緒的。

在一個執行緒被建立並完成初始化以後,Java 的執行時系統自動呼叫 run() 方法,正是通過 run() 方法才使得建立執行緒的目的得以實現。

執行緒一共有 4 中狀態:新建(new)、可執行狀態(runnable)、死亡(dead)及阻塞(blocked),如圖所示:

(1)新建

執行緒物件剛剛建立,還沒有啟動,處於不可執行狀態,如:

Thread thread = new Thread("Test");

此時執行緒 thread 處於新建狀態,但已有了相應的記憶體空間以及其他資源。

(2)可執行狀態(runnable)

此時的執行緒已經啟動,處於執行緒的 run() 方法之中。這種情況下執行緒可能正在執行,也可能沒有執行,只要 CPU 一空閒,馬上就會執行。可以執行但並沒在執行的執行緒都排在一個佇列之中,這個佇列稱為就緒佇列。

呼叫執行緒 start() 方法可使執行緒處於 “可執行” 狀態,如:

thread.start();

(3)死亡(dead)

執行緒死亡的原因有兩個:一是 run() 方法中最後一個語句執行完畢;二是當執行緒遇到異常退出時便進入了死亡狀態。

(4)阻塞(blocked)

一個正在執行的執行緒因特殊原因被暫停執行,就進入阻塞狀態。阻塞時執行緒不能進入就緒佇列排隊,必須等到引起阻塞的原因消除,才可重新進入佇列排隊。

引起阻塞的原因有很多,不同原因要用不同的方法解除。如 sleep() 和 wait() 就是兩個常用的引起阻塞的方法。

(5)中斷執行緒

當 run() 執行結束返回時,執行緒自動終止。

在程式中常常呼叫 interrupt() 來終止執行緒。interrupt() 不僅可中斷正在執行的執行緒,而且也能中斷處於 blocked 狀態的執行緒,此時 interrupt() 會丟擲一個 InterruptedException 異常。

Java 提供了幾個用於測試執行緒是否被中斷的方法:

  • void interrupt() ————向一個執行緒傳送一箇中斷請求,同時把這個執行緒的 “interrupted” 狀態置為 true。若該執行緒處於 “blocked” 狀態,會丟擲一個 InterruptedException 異常。

  • static boolean interrupted() ————檢測當前執行緒是否已被中斷,並重置狀態 “interrupted” 值。即如果連續兩次呼叫該方法,則第二次呼叫將返回 false。

  • boolean isInterrupted ————檢測當前執行緒是否已被中斷,不改變狀態 “interrupted” 值。