java核心技術卷I-線程

線程

多線程程序在較低的層次上擴展了多任務的概念:一個程序同時執行多個任務。通常,每一個任務稱爲一個線程( thread), 它是線程控制的簡稱。可以同時運行一個以上線程的程序稱爲多線程程序(multithreaded)。

多進程與多線程區別

本質的區別在於每個進程擁有自己的一整套變量, 而線程則共享數據(同時也帶來了風險)。
共享變量使線程之間的通信比進程之間的通信更有效、 更容易。
與進程相比較, 線程更“ 輕量級”, 創建、 撤銷一個線程比啓動新進程的開銷要小得多。

創建線程

構造線程的基本方法

public interface Runnable
{
	void run();
}
Runnable r = () -> { task code };
Thread t = new Thread(r);
t.start();

或者繼承Thread類:

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

不要調用 Thread 類或 Runnable 對象的 run 方法。 直接調用 run 方法, 只會執行同一個線程中的任務, 而不會啓動新線程。應該調用 Thread.start 方法。這個方法將創建一個執行 run 方法的新線程

中斷線程

當線程的 run 方法執行方法體中最後一條語句後, 並經由執行 return 語句返冋時,或者出現了在方法中沒有捕獲的異常時,線程將終止。 在 Java 的早期版本中, 還有一個stop方法, 其他線程可以調用它終止線程。但是, 這個方法現在已經被棄用了。
沒有可以強制線程終止的方法。然而,interrupt 方法可以用來請求終止線程。
當對一個線程調用 interrupt 方法時,線程的中斷狀態將被置位。這是每一個線程都具有的 boolean 標誌。每個線程都應該不時地檢査這個標誌, 以判斷線程是否被中斷。
要想弄清中斷狀態是否被置位,首先調用靜態的 Thread.currentThread 方法獲得當前線
程, 然後調用 islnterrupted 方法:

while (!Thread.currentThread().islnterrupted() && more work to do)
{
	do more work
}

但是, 如果線程被阻塞, 就無法檢測中斷狀態。這是產生 InterruptedException 異常的地方。當在一個被阻塞的線程(調用 sleep 或 wait) 上調用 interrupt 方法時,阻塞調用將會被Interrupted Exception 異常中斷。
沒有任何語言方面的需求要求一個被中斷的線程應該終止。中斷一個線程不過是引起它的注意。被中斷的線程可以決定如何響應中斷。某些線程是如此重要以至於應該處理完異常後, 繼續執行,而不理會中斷。但是,更普遍的情況是,線程將簡單地將中斷作爲一個終止的請求。

Runnable r = () -> {
	try
	{
		while (!Thread.currentThread().islnterrupted0 && more work to do)
		{
			do more work
		}
	}catch(InterruptedException e){
		// thread was interr叩ted during sleep or wait
	}finally{
		clean up,if required
	}
	// exiting the run method terminates the thread
};

如果在每次工作迭代之後都調用 sleep 方法(或者其他的可中斷方法,) islnterrupted 檢測既沒有必要也沒有用處。如果在中斷狀態被置位時調用 sleep 方法,它不會休眠。相反,它將清除這一狀態(丨)並拋出 IntemiptedException。因此, 如果你的循環調用 sleep,不會檢測中斷狀態。
有兩個非常類似的方法,interrupted 和 islnterrupted。Interrupted 方法是一個靜態方法, 它檢測當前的線程是否被中斷。 而且, 調用 interrupted 方法會清除該線程的中斷狀態。另一方面,islnterrupted 方法是一個實例方法,可用來檢驗是否有線程被中斷。調用這個方法不會改變中斷狀態。
java.Iang.Thread 1.0部分方法

void interrupts()

向線程發送中斷請求。線程的中斷狀態將被設置爲 true。如果目前該線程被一個 sleep調用阻塞,那麼,InterruptedException 異常被拋出。

static boolean interrupted()

測試當前線程(即正在執行這一命令的線程)是否被中斷。注意,這是一個靜態方法。這一調用會產生副作用—它將當前線程的中斷狀態重置爲 false。

boolean islnterrupted()

測試線程是否被終止。不像靜態的中斷方法,這一調用不改變線程的中斷狀態。

static Thread currentThread()

返回代表當前執行線程的 Thread 對象

線程狀態

線程可以有如下 6 種狀態:

New (新創建)
Runnable (可運行)
Blocked (被阻塞)
Waiting (等待)
Timed waiting (計時等待)
Terminated (被終止)

在這裏插入圖片描述
要確定一個線程的當前狀態, 可調用 getState 方法

新創建線程

當用 new 操作符創建一個新線程時,如 newThread(rs), 該線程還沒有開始運行。這意味着它的狀態是 new。當一個線程處於新創建狀態時,程序還沒有開始運行線程中的代碼。在線程運行之前還有一些基礎工作要做

可運行線程

一旦調用 start 方法,線程處於 runnable 狀態。一個可運行的線桿可能正在運行也可能沒有運行, 這取決於操作系統給線程提供運行的時間。
一旦一個線程開始運行,它不必始終保持運行。事實上,運行中的線程被中斷,目的是爲了讓其他線程獲得運行機會。線程調度的細節依賴於操作系統提供的服務。搶佔式調度系統給每一個可運行線程一個時間片來執行任務。當時間片用完,操作系統剝奪該線程的運行權, 並給另一個線程運行機會。當選擇下一個線程時, 操作系統考慮線程的優先級。
在具有多個處理器的機器上,每一個處理器運行一個線程, 可以有多個線程並行運行。當然,如果線程的數目多於處理器的數目, 調度器依然採用時間片機制。

在任何給定時刻,一個可運行的線程可能正在運行也可能沒有運行

被阻塞線程和等待線程

當線程處於被阻塞或等待狀態時,它暫時不活動。它不運行任何代碼且消耗最少的資源。直到線程調度器重新激活它。

當一個線程試圖獲取一個內部的對象鎖, 而該鎖被其他線程持有(而不是 javiutiUoncurrent 庫中的鎖), 則該線程進人阻塞狀態。當所有其他線程釋放該鎖,並且線程調度器允許本線程持有它的時候,該線程將變成非阻塞狀態。
當線程等待另一個線程通知調度器一個條件時,它自己進入等待狀態。在調用Object.wait 方法或 Thread.join 方法, 或者是等待 java,util.concurrent 庫中的 Lock 或 Condition 時, 就會出現這種情況。實際上,被阻塞狀態與等待狀態是有很大不同的。
有幾個方法有一個超時參數。調用它們導致線程進人計時等待( timed waiting ) 狀態。這一狀態將一直保持到超時期滿或者接收到適當的通知。帶有超時參數的方法有Thread.sleep 和 Object.wait、Thread.join、 Lock,tryLock 以及 Condition.await 的計時版。

當一個線程被阻塞或等待時(或終止時,) 另一個線程被調度爲運行狀態。當一個線程被重新激活(例如, 因爲超時期滿或成功地獲得了一個鎖,) 調度器檢查它是否具有比當前運行線程更高的優先級。如果是這樣,調度器從當前運行線程中挑選一個, 剝奪其運行權,選擇一個新的線程運行

被終止的線程

線程因如下兩個原因之一而被終止:

因爲 run 方法正常退出而自然死亡
因爲一個沒有捕獲的異常終止了 run 方法而意外死亡。

線程屬性

包括:線程優先級、守護線程、 線程組以及處理未捕獲異常的處理器

線程優先級

在 Java 程序設計語言中,每一個線程有一個優先級。默認情況下, 一個線程繼承它的父線程的優先級。可以用 setPriority 方法提高或降低任何一個線程的優先級。可以將優先級設置爲在 MIN_PRIORITY (在 Thread 類中定義爲 1 ) 與 MAX_PRIORITY (定義爲 10 ) 之間的任何值。NORM_PRIORITY 被定義爲 5

守護線程

可以通過調用

t.setDaemon(true);

將線程轉換爲守護線程(daemon thread。) 這樣一個線程沒有什麼神奇。守護線程的唯一用途是爲其他線程提供服務。

未捕獲異常處理器

線程的 run方法不能拋出任何受查異常, 但是,非受査異常會導致線程終止。在這種情況下,線程就死亡了。
但是,不需要任何 catch子句來處理可以被傳播的異常。相反,就在線程死亡之前, 異常被傳遞到一個用於未捕獲異常的處理器。
該處理器必須屬於一個實現 Thread.UncaughtExceptionHandler 接口的類。這個接口只有—個方法。

void uncaughtException(Thread t, Throwable e)

可以用 setUncaughtExceptionHandler 方法爲任何線程安裝一個處理器。也可以用Thread類的靜態方法 setDefaultUncaughtExceptionHandler 爲所有線程安裝一個默認的處理器。替換處理器可以使用日誌 API 發送未捕獲異常的報告到日誌文件。
ThreadGroup 類實現 Thread.UncaughtExceptionHandler 接口。它的 uncaughtException 方
法做如下操作:

1 ) 如果該線程組有父線程組, 那麼父線程組的 uncaughtException 方法被調用。
2 ) 否則, 如果Thread.getDefaultExceptionHandler 方法返回一個非空的處理器, 則調用該處理器。
3 ) 否則,如果Throwable 是 ThreadDeath 的一個實例, 什麼都不做。
4 ) 否則,線程的名字以及 Throwable的棧軌跡被輸出到 System.err 上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章