Java多線程編程核心技術-第7章-拾遺增補-讀書筆記

第 7 章 拾遺增補

本章主要內容

線程組的使用。
如何切換線程狀態。
SimpleDataFormat 類與多線程的解決辦法。
如何處理線程的異常。

7.1 線程的狀態

  線程對象在不同的運行時期有不同的狀態,狀態信息就存在於 State 枚舉類中,如下圖:

  每個枚舉類型的解釋如下圖:

  調用與線程有關的方法是造成線程狀態改變的主要原因,其因果關係如下圖:

  在調用與線程有關的方法後,會進入不同的次線程狀態,這些狀態之間某些是可雙向切換的,比如 WAITING 和 RUNNING 狀態之間可以循環地進行切換;而有些是單向切換的,比如線程銷燬後並不能自動進入 RUNNING 狀態。

7.1.1 驗證 NEW、RUNNABLE 和 TERMINATED

  首先驗證的是 NEW、RUNNABLE 及 TERMINATED 狀態,NEW 狀態是線程實例化後還從未執行 start() 方法時的狀態,而 RUNNABLE 狀態是線程進入運行的狀態,TERMINATED 是線程被銷燬時的狀態。

7.1.2 驗證 TIMED_WAITING

  線程狀態 TIMED_WAITING 代表線程執行了 Thread.sleep() 方法,呈等待狀態,等待時間到達,繼續向下運行。

  執行 sleep() 方法後線程的狀態枚舉值就是 TIMED_WAITING。

7.1.3 驗證 BLOCKED

  BLOCKED 狀態出現在一個線程在等待鎖的時候。

7.1.4 驗證 WAITING

  狀態 WAITING 是線程執行了 Object.wait() 方法後所處的狀態。

  執行 wait() 方法後線程的狀態枚舉值就是 WAITING。

7.2 線程組

  可以吧線程歸屬到某一個線程組中,線程組中可以有線程對象,也可以有線程組,組中還可以有線程。這樣的組織結構有些類似於樹的形式。如下圖:

  線程組的作用是,可以批量的管理線程或線程組對象,有效地對線程或線程組對象進行組織。

7.2.1 線程對象關聯線程組:1 級關聯

  所謂的 1 級關聯就是父對象中有子對象,但並不創建子孫對象。這種情況經常出現在開發中,比如創建一些線程時,爲了有效地對這些線程進行組織管理,通常的情況下是創建一個線程組,然後再將部分線程歸屬到該組中。這樣的處理可以對零散的線程對象進行有效的組織與規劃。

7.2.2 線程對象關聯線程組:多級關聯

  所謂的多級關聯就是父對象中有子對象,子對象中再創建子對象,也就是出現子孫對象的效果了。但是此種寫法在開發中不太常見,如果線程樹結構設計得非常複雜反而不利於線程對象的管理,但 JDK 卻提供了支持多級關聯的線程樹結構。

  線程必須啓動然後纔可以歸到組中。

  線程必須在運行狀態纔可以受組管理。

7.2.3 線程組自動歸屬特性

  自動歸屬就是自動歸到當前線程組中。

  方法 activeGroupCount() 取得當前線程組對象中的子線程組數量。

  方法 enumerate() 的作用是將線程組中的子線程組以複製的形式拷貝到 ThreadGroup() 數組對象中。

  在實例化一個 ThreadGroup 線程組 x 時如果不指定所屬的線程組,則 x 線程組自動歸到當前線程對象所屬的線程組中,也就是隱式地在一個線程組中添加了一個子線程組。

7.2.4 獲取根線程組

  JVM 的根線程組就是 system,再取其父線程組則出現空異常。

7.2.5 線程組裏加線程組

ThreadGroup newGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(),"newGroup");

7.2.6 組內的線程批量停止

  通過將線程歸屬到線程組中,當調用線程組 ThreadGroup 的 interrupted() 方法時,可以將該組中的所有正在運行的線程批量停止。

7.2.7 遞歸與非遞歸取得組內對象

//分配控件,但不一定全部用完
ThreadGroup[] listGroup1 = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
//傳入 true 是遞歸取得子組及子孫組,false是隻取子組
Thread.currentThread().getThreadGroup().enumerate(listGroup1,true);

7.3 使線程具有有序性

  正常的情況下,線程在運行時多個線程之間執行任務的時機是無序的。可以通過改造代碼的方式使它們運行具有有序性。

  使用 synchronized 同步的方法讓線程順序執行。

7.4 SimpleDateFormat 非線程安全

  類 SimpleDateFormat 主要負責日期的轉換與格式化,但在多線程的環境中,使用此類容易造成數據轉換及處理的不準確,因爲 SimpleDateFormat 類並不是線程安全的。

7.4.1 出現異常

  使用單例的 SimpleDateFormat 類在多線程的環境中處理日期,極易出現日期轉換錯誤的情況。

7.4.2 解決異常方法 1

  解決處理錯誤的方法就是創建了多個 SimpleDateFormat 類的實例。

7.4.3 解決異常方法 2

  ThreadLocal 類能使線程綁定到指定的對象。使用該類也可以解決多線程環境下 SimpleDateFormat 類處理錯誤的情況。

private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>();

7.5 線程中出現異常的處理

  在 Java 的多線程技術中,可以對多線程中的異常進行“捕捉”,使用的是 UncaughtExceptionHandler 類,從而可以對發送的異常進行有效的處理。

  方法 setUncaughtExceptionHandler() 的作用是對指定的線程對象設置默認的異常處理器。

  方法 setUncaughtExceptionHandler() 是給指定線程對象設置的異常處理器。在 Thread 類中還可以使用 setDefaughtExceptionHandler() 方法對所有線程對象設置異常處理器。

  方法 setDefaultUncaughtExceptionHandler() 的作用是爲指定線程類的所有線程對象設置默認的異常處理器。

7.6 線程組內處理異常

  在默認的情況下,線程組中的一個線程出現異常不會影響其他線程的運行。

  Thread 的 uncaughtException(Thread t,Throwable e) 方法中的 t 參數是出現異常的線程對象。

  需要注意的是,使用自定義 java.lang.ThreadGroup 線程組,並且重寫 uncaughtException 方法處理組內線程中斷行爲時,每個線程對象中的 run() 方法內部不要有異常 catch 語句,如果有 catch 語句,則 public void uncaughtException(Thread t,Throwable e) 方法不執行。

7.7 線程異常處理的傳遞

  測試若干個線程異常處理的方式放在一起運行的情況。

  ThreadGroup 覆蓋實現 uncaughtException(Thread t,Throwable e) 方法,並且調用 Thread 的 setUncaughtExceptionHandler() 與 setDefaultUncaughtExceptionHandler() 方法設置對象與全局的異常處理類。

  運行一個線程(不設置組),即調用 setUncaughtExceptionHandler() 方法,也調用 setDefaultUncaughtExceptionHandler() 方法出現異常只會回調對象的異常處理(setUncaughtExceptionHandler())。

  運行一個線程(不設置組),不調用 setUncaughtExceptionHandler() 方法,只調用 setDefaultUncaughtExceptionHandler() 方法, 則不會回調任何的異常處理。

  創建一個線程組,將線程加入到線程組中,並且調用 Thread 的 setUncaughtExceptionHandler() 與 setDefaultUncaughtExceptionHandler()方法,線程異常則調用對象的異常處理(setUncaughtExceptionHandler())。

  創建一個線程組,將線程加入到線程組中,只調用 Thread 的 setDefaultUncaughtExceptionHandler()方法,線程異常則調用全局的異常處理(setDefaultUncaughtExceptionHandler())。

  創建一個線程組,將線程加入到線程組中,不調用 Thread 的 setUncaughtExceptionHandler() 與 setDefaultUncaughtExceptionHandler()方法,,線程異常則調用線程組的異常處理(ThreadGroup::uncaughtException(Thread t,Throwable e))。

  如果想要打印“靜態的異常處理”的信息,則必須在 public void uncaughtException(Thread t,Throwable e)方法中加上 super.uncaughtException(t,e);代碼。

7.8 本章總結

  本章彌補了前面幾個章節遺漏的技術空白點。

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