天天看點

任務執行(第六章)

任務邊界:當圍繞“任務執行”來設計應用程式時,第一步就是要找出清晰的任務邊界。

線程生命周期的開銷非常高:線程的建立于銷毀

資源消耗:活躍的線程會消耗系統資源,尤其是記憶體。如果可運作的線程數量多于可用處理器的數量,那麼有些線程将閑置。是以,如果已經擁有足夠多的線程使CPU保持忙碌狀态,那麼建立再多的線程反而會降低性能

穩定性:在可建立線程的數量上存在一定限制,這個閑置值将随平台的不同而不同,并且受多個因素閑置。如果破壞了這些限制,那麼可能抛出OutOfMemoryError異常

Executor架構能支援多種不同類型的任務執行政策,它提供了一種标準的方法将任務的送出過程與執行過程解耦,并用Runnable來表示任務。Executor的實作還提供了對生命周期的支援,以及統計資訊收集、應用程式管理機制和性能監視等機制。

Executor基于生産者----消費者模式,送出任務的操作相當于生産者,執行任務的線程相當于消費者。

Executor的生命周期

JVM隻有在所有(非守護)線程都終止後才會退出,是以,如果Executor沒有正确關閉,那麼JVM将無法退出。

Executor執行的任務有4個證明周期階段:建立、送出、開始和完成。已送出但尚未開始的任務可以取消,但對于已經開始執行的任務,隻有當他們響應中斷時才能取消。

Executor擴充了ExecutorService接口,用于管理生命周期:

Executor的缺陷:

Executor使用Runnable作為基本的任務标志形式,但Runnable中的run()不能傳回值也不能抛出異常

在執行政策中定義了任務執行的“What、Where、When、How”等方面。包括:

線程池指管理一組同構工作線程的資源池。

可以通過調用Executor中的一些靜态函數建立線程池:

newFixedThreadPool:建立一個固定長度的線程池,每當送出一個任務時就建立一個線程,直到建立的線程數量達到最大,此後線程的數量不會再變化。如果某個線程由于發生未預期的Exception而結束,那麼線程會補充一個新的線程

newCachedThreadPool:建立一個可緩存的線程池,如果線程池的規模超過了處理需求,那麼将回收空閑的線程,而當需求增加時,則可以添加新的線程,線程池的規模不存在人任何限制

newSingleThreadExecutor:單線程的Executor,它建立單個工作者線程來執行任務,如果這個線程異常結束,會建立一個新的線程來代替,其能確定依照任務在隊列中的順序串行序執行

new ScheduledThreadPool:建立一個固定長度的線程池,而且以延時或定時的方式來執行順序

Timer類負責管理延遲任務以及周期任務,但是Timer類存在一些缺陷,應該考慮使用ScheduledThreadPool類代替它。

Timer類的缺陷

Timer在執行所有定時任務時隻會建立一個線程,如果某個任務的延時時間過長,那麼将破壞其他TimerTask的定時精确性。

如果TimerTask抛出了一個未受檢查的異常,由于Timer線程并不捕獲異常,是以Timer将終止線程的執行。

Callable提供了一種相比Runnable更好的抽象:call,call()有傳回值(要用Callable表示無傳回值的任務,使用Callable),并且允許抛出異常。

Future表示一個任務的生命周期,并提供了相應的方法來判斷是否已經完成或取消,以及擷取任務的結果和取消任務等。Future意味着任務的生命周期隻能前進,不能後退。

如果任務抛出了異常,那麼get将異常封裝為ExecutorException并重新抛出,并且可以通過getCause來獲得被封裝的初始異常,如果任務被取消,那麼get将抛出 CancellationException