1. 程式人生 > >取消與關閉

取消與關閉

無法 RR 生命 自己 span super 異常 tro get

7 取消與關閉

7.1.5通過Future來實現取消

技術分享圖片

Future.get拋出異常,當你知道不在需要這個結果,可以調用Future.caneel來取消任務。

7.1.6 處理不可中斷的阻塞(非標準的取消)

在Java庫中,許多可阻塞的方法都是通過提前返回或者拋出InterruptedException來響應中斷請求的,然而,並非所有的可阻塞方法或者阻塞機制都能響應中斷;如果一個線程由於執行同步的Socket I/O或者等待獲得內置鎖而阻塞,那麽中斷請求只能設置線程的中斷狀態,除此之外沒有其他任何作用。

對於那些由於執行不可中斷操作而被阻塞的線程,可以使用類似於中斷的手段來停止這些線程,但這要求我們必須知道線程阻塞的原因。

Java.io包中的同步Socket I/O。在服務器應用程序中,最常見的阻塞I/O形式就是對套接字進行讀取和寫人。雖然InputStream和OutputStream中的read和write等方法都不會響應中斷,但通過關閉底層的套接字,可以使得由於執行read或write等方法而被阻塞的線程拋出一個SocketException。

Java.lo包中的同步I/O。當中斷一個正在InterruptibleChannel上等待的線程時,將拋出ClosedByInterruptException並關閉鏈路(這還會使得其他在這條鏈路上阻塞的線程同樣拋出ClosedByInterruptException )。當關閉一個InterruptibleChannel時,將導致所有在鏈路操作上阻塞的線程都拋出AsynchronousCloseException。大多數標準的Channel都實現了IntemtptibleChannel。

Selector的異步I/O。如果一個線程在調用Selector.select方法(在java.nio.channels中)

時阻塞了,那麽調用close或wakeup方法會使線程拋出ClosedSelectorException並提前返回。

獲取某個鎖。如果一個線程由於等待某個內置鎖而阻塞,那麽將無法響應中斷,因為線程認為它肯定會獲得鎖,所以將不會理會中斷請求。但是,在Lock類中提供了lockInterruptibly方法,該方法允許在等待一個鎖的同時仍能響應中斷。

技術分享圖片

7.1.7 采用newTaskFor來封裝非標準的取消

這是Java 6在ThreadPoolExecutor中的新增功能。當把一個Callable提交給ExecutorService時submit方法會返回一個Future, 我們可以通過這個Future來取消任務。newTaskFor是一個工廠方法,_它將創建Future來代表任務。newTaskFor還能返回一個RunnableFuture接口,該接口擴展了Future和Runnable(並由FutureTask實現)。

通過改寫interrupt方法,ReaderThread可以取消基於套接字的線程。同樣,通過改寫任務的Future.cancel方法也可以實現類似的功能。

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

SocketUsingTask實現了CancellableTask,並定義了Future.cancel來關閉套接字和調用super.cancel。如果SocketUsingTask通過其自己的Future來取消,那麽底層的套接字將被關閉並且線程將被中斷。因此它提高了任務對取消操作的響應性:不僅能夠在調用可中斷方法的同時確保響應取消操作,而且還能調用可阻調的套接字I/O方法。

7.2停止基於線程的服務

應用程序通常會創建擁有多個線程的服務,例如線程池,並且這些服務的生命周期通常比創建它們的方法的生命周期更長。如果應用程序淮備退出,那麽這些服務所擁有的線程也需要結束。由於無法通過搶占式的方法來停止線程,因此它們需要自行結束。

封裝原則: 除非擁有某個線程,否則不能對該線程進行操控。線程池是其工作者線程的所有者。如果要中斷這些線程,那麽應該使用線程池。

線程的所有權是不可傳遞的。應用程序可以擁有服務,服務可以擁有工作者線程。但應用程序並不能擁有工作者線程,因此應用程序不能直接停止工作者線程。

取消與關閉