java併發編程(七)線程的取消與關閉

中斷

要使任務和線程安全、快速、可靠的停止下來並不是一件容易的事情。java沒有提供任何機制來安全的終止線程。
但它提供了中斷(Interruption),這是一種協作機制能夠使一個線程終止另一個線程的當前工作。
通常,中斷是實現取消的最合理方式。

中斷是禮貌地請求另一個線程在它願意並且方便的時候停止它正在做的事情。有些方法,例如 Thread.sleep(),wait,jion很認真地對待這樣的請求,但每個方法不是一定要對中斷作出響應。

interrupt()實現中斷

Thread中斷相關操作

  • interrupt: 用於中斷目標線程
  • isInterrupted: 用於檢測目標線程是否會中斷
  • Thread.interrupted: 用於清除當前線程的中斷狀態,並返回之前的中斷狀態,這是清除中斷狀態的唯一方法

interrupt()會使線程拋出interruptedException,線程內捕捉該異常並處理結束任務比如跳出循環等。
注意線程內拋出interruptedException時一定要處理,如果不處理的話這個線程就屏蔽了中斷。

Future實現取消

通常使用現有的類比自行編寫更好,Future提供了這樣的方法。
future.cancel(boolean a);a爲ture時表示結束這個正在運行的任務,如果a爲false表示如果這個任務還沒運行的話就不要運行了。
所以在我們調用future.get的時候如果拋出異常,而且我們知道這個時候不需要結果時可以使用future.cancel(ture)取消任務。

處理不可中斷請求

不是所有阻塞方法都能響應中斷,例如I/O阻塞或者等待內置鎖而阻塞,這種情況下中斷請求除了設置中斷狀態外沒有任何作用。
等待內置鎖時線程認爲它一定能獲得鎖所以不會理會中斷請求,但是Lock類提供了一種允許等待鎖的同時仍然能響應中斷請求

停止基於線程的服務(線程池等)

關閉ExecutorService
ExecutorService
ExecutorService提供兩個關閉的方法,shutdown 和shutdownNow。shutdownNow首先關閉當前執行線程,然後返回未執行的任務,而shutdown則等待執行完成。兩種方法差別在於安全性和響應性。shutdown關閉的慢但是更加安全。

JVM關閉鉤子

關閉鉤子本質上是一個線程(也稱爲Hook線程),用來監聽JVM的關閉。通過使用Runtime的addShutdownHook(Thread hook)可以向JVM註冊一個關閉鉤子。Hook線程在JVM 正常關閉纔會執行,在強制關閉時不會執行。

對於一個JVM中註冊的多個關閉鉤子它們將會併發執行,所以JVM並不能保證它的執行順行。Hook線程會延遲JVM的關閉時間,這就要求在編寫鉤子過程中必須要儘可能的減少Hook線程的執行時間。另外由於多個鉤子是併發執行的,那麼很可能因爲代碼不當導致出現競態條件或死鎖等問題,爲了避免該問題,強烈建議在一個鉤子中執行一系列操作。
例如通過Hook實現臨時文件清理

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                System.out.println("清理臨時文件");
            }
        }));

總結

java並沒有提供搶佔式的機制來取消線程,它提供了了一種協作式的中斷機制。Future和Executor框架可以幫助我們構建可取消的任務,避免我們手動構建。

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