1. 程式人生 > >多線程狀態及線程池管理

多線程狀態及線程池管理

exe i/o wait 存儲 auto alt 周期 queue imu

一. 線程狀態類型 1. 新建狀態(New):新創建了一個線程對象。 2. 就緒狀態(Runnable):線程對象創建後,其他線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲取CPU的使用權。 3. 運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。 4. 阻塞狀態(Blocked):阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種: (一)、等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。 (二)、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。 (三)、其他阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態。 5. 死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。 技術分享圖片

技術分享圖片

技術分享圖片 技術分享圖片 二Executor框架的成員 技術分享圖片

技術分享圖片 采取上述步驟的總體設計思路,是為了在執行execute()方法時,盡可能地避免獲取全局鎖(那將會是一個嚴重的可伸縮瓶頸)。在ThreadPoolExecutor完成預熱之後(當前運行的線程數大於等於corePoolSize),幾乎所有的execute()方法調用都是執行將任務存儲在隊列裏,而步驟2不需要獲取全局鎖。 2.1 ThreadPoolExecutor 2.1.1創建線程 new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,milliseconds,runnableTaskQueue, handler);或者使用工廠類Executors來創建。 也可以可以創建三種 singleThreadExecutor、FixedThreadPool和CachedThreadPool。 FixedThreadPool使用無界隊列LinkedBlockingQueue作為線程池的工作隊列(隊列的容量為Integer.MAX_VALUE)。使用無界隊列作為工作隊列會對線程池帶來如下影響。 1)當線程池中的線程數達到corePoolSize後,新任務將在無界隊列中等待,因此線程池中的線程數不會超過corePoolSize。 2)由於1,使用無界隊列時maximumPoolSize將是一個無效參數。 3)由於1和2,使用無界隊列時keepAliveTime將是一個無效參數。 4)由於使用無界隊列,運行中的FixedThreadPool(未執行方法shutdown()或shutdownNow())不會拒絕任務(不會調用RejectedExecutionHandler.rejectedExecution方法)。 SingleThreadExecutor的corePoolSize和maximumPoolSize被設置為1,使用無界隊列LinkedBlockingQueue作為線程池的工作隊列,影響與FixedThreadPool相同 CachedThreadPool的corePoolSize被設置為0,即corePool為空;maximumPoolSize被設置為Integer.MAX_VALUE,即maximumPool是無界的。這裏把keepAliveTime設置為60L,意味著 空閑線程等待新任務的最長時間為60秒,空閑線程超過60秒後將會被終止。使用無界隊列LinkedBlockingQueue作。極端情況下會因為創建過多線程而耗盡CPU和內存資源。 2.1.2執行線程 execute()方法用於提交不需要返回值的任務,所以無法判斷任務是否被線程池執行成功。 submit()方法用於提交需要返回值的任務。線程池會返回一個future類型的對象,通過這個future對象可以判斷任務是否執行成功,並且可以通過future的get()方法來獲取返回值,get()方法會阻塞當前線程直到任務完成,而使用get(long timeout,TimeUnit unit)方法則會阻塞當前線程一段時間後立即返回,這時候有可能任務沒有執行完。 threadsPool.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }); 2.2ScheduledThreadPoolExecutor ·ScheduledThreadPoolExecutor。包含若幹個線程,適用於需要多個後臺線程執行周期任務,同時為了滿足資源管理的需求而需要限制後臺線程的數量的應用場景。 1)當調用ScheduledThreadPoolExecutor的scheduleAtFixedRate()方法或者scheduleWith-FixedDelay()方法時,會向ScheduledThreadPoolExecutor的DelayQueue添加一個實現了RunnableScheduledFutur接口的ScheduledFutureTask。 2)線程池中的線程從DelayQueue中獲取ScheduledFutureTask,然後執行任務。 ·SingleThreadScheduledExecutor。只包含一個線程,適用於需要單個後臺線程執行周期任務,同時需要保證順序地執行各個任務的應用場 3.合理地配置線程池 要想合理地配置線程池,就必須首先分析任務特性,可以從以下幾個角度來分析。 ·任務的性質:CPU密集型任務、IO密集型任務和混合型任務。 ·任務的優先級:高、中和低。 ·任務的執行時間:長、中和短。 ·任務的依賴性:是否依賴其他系統資源,如數據庫連接。 性質不同的任務可以用不同規模的線程池分開處理。CPU密集型任務應配置盡可能小的線程,如配置Ncpu+1個線程的線程池。由於IO密集型任務線程並不是一直在執行任務,則應配置盡可能多的線程,如2*Ncpu。混合型的任務,如果可以拆分,將其拆分成一個CPU密集型任務 和一個IO密集型任務,只要這兩個任務執行的時間相差不是太大,那麽分解後執行的吞吐量將高於串行執行的吞吐量。如果這兩個任務執行時間相差太大,則沒必要進行分解。建議使用有界隊列。 I/O bound 指的是系統的CPU效能相對硬盤/內存的效能要好很多,此時,系統運作,大部分的狀況是 CPU 在等 I/O (硬盤/內存) 的讀/寫,此時 CPU Loading 不高。 CPU bound 指的是系統的 硬盤/內存 效能 相對 CPU 的效能 要好很多,此時,系統運作,大部分的狀況是 CPU Loading 100%,CPU 要讀/寫 I/O (硬盤/內存),I/O在很短的時間就可以完成,而 CPU 還有許多運算要處理,CPU Loading 很高

多線程狀態及線程池管理