1. 程式人生 > >java 多線程之取消與關閉

java 多線程之取消與關閉

ket execute 是否 擁有 函數 恢復 響應 lean shu

  要使線程安全,快速,可靠的停下來並不是一件容易的事情。java並沒有提供任何機制來安全的終止線程。但是java提供了中斷(interrupt)使一個線程可以終止另一個線程的當前工作

  每個線程都有一個boolean類型的中斷狀態。當中斷線程時,這個線程的中斷狀態將被設置未true。Thread包含了中斷線程以及檢查線程中斷的方法。

    interrupt()方法能中斷目標線程。

    boolean isInterrupt()方法能返回目標線程是否中斷的狀態。

    static boolean interrupted() 將返回並清除線程當前的中斷狀態,這個也是清除線程中斷狀態的唯一方法。

  調用interrupt()方法並不意味著立即停止目標線程正在進行的工作,而只是傳遞了請求中斷的消息。然後由線程在下一個合適的時機中斷自己。

  中斷策略

  每個線程都應該包含自己的終端策略,以響應中斷狀態。中斷策略規定了線程如何響應中斷請求-----當發現中斷請求時應該做哪些操作,哪些工作單元對中斷來說是原子的,以及以多塊的速度相應中斷。

  響應中斷

  . 當調用可中斷的阻塞函數時有兩種使用策略可用於處理interruption異常

    1.傳遞異常,從而使你的方法也變成可中斷的阻塞方法。

      傳遞異常只需要在方法外加上 throws interruptedException就可以了,

    2.恢復中斷狀態,從而使調用棧中的上層代碼能夠對其進行處理。

      可以調用interrupt()方法來恢復中斷狀態。

  二. 如果代碼不會調用可中斷的阻塞方法,那麽仍然可以通過輪詢當前線程中的中斷狀態來相應中斷。

  通過Future實現取消

  調用ExecutorService.submit方法將返回一個future對象。

  Future.cancel(boolean b).可用於取消當前任務。若b設置為true,則表示若線程正在運行則中斷,若設置為false,若還沒有運行則不會運行,則表示若正在運行就不中斷,還未運行就不在執行。返回值只是表示是否設置中斷狀態成功,而不是線程已經中斷。

  處理不可中斷的阻塞

  java.io包中的同步socket,io,可直接關閉底層socket套接字。

  java.io可關閉鏈路

  selector異步io可調用close或wakeup方法提前返回。

  關閉基於線程的服務

  應用程序通常創建擁有多個線程的服務。這些服務的生命周期通常比創建他們的方法要長,如果應用程序準備退出,那麽服務擁有的線程也需要結束,因此服務應該提供生命周期方法,來關閉它自己以及它所擁有的線程。

  ExecutorService就提供了shutdown和shutdownnow兩個方法來停止服務。shutdownnow方法會首先停止接受新的任務,然後關閉正在執行的任務,最後返回已經提交單還沒有執行的任務。而shutdown方法會首先停止接受新的任務,然後等待隊列中所有已經提交的任務完成,最後執行關閉。shutdownnow擁有更好的響應性但安全性較差。

  另一種關閉生產者---消費者服務的方式是使用毒丸對象。只有在生產者和消費者數量都已知的情況下才可以使用毒丸對象。並且只有在無界隊列中毒丸對象才能正常的工作。而且當生產者和消費者數量都很大時,這種方法將變的難以使用。

  處理非正常的線程終止

  1.通過主動的方式處理。在任務處理線程的生命周期中,將通過某種抽象機制來調用許多未知的代碼,我們應該對這些線程中執行的代碼能否表現出正確的行為表示懷疑,因此這些線程應該在try-catch代碼塊中執行,這樣就能捕獲那些未檢查的異常了,或者可以在try-finally代碼塊確保框架能夠知道線程非正常退出的情況,並做出正確的相應。

  2.通過ThreadAPI提供的UncaughtExceptionHandler處理。UncaughtExceptionHandler能夠檢測出某個線程由於未補獲異常而終止的情況。只有通過execute方法提交的任務才能將異常交給未補獲異常處理器處理,通過submit提交的方法,無論時拋出檢查的還是未檢查的異常都將視為是任務返回狀態的一部分。如果一個由submit提交的任務拋出了異常,那麽這個異常將會被Future.get封裝在ExecueExcetion中重新拋出。

  這兩種方法時互補的,通過將這兩種方法有效的結合在一起就能有效的防止線程泄露的問題。

java 多線程之取消與關閉