Executors
1.概述
初學Java多線程,常使用Thread與Runnable創建、啟動線程。如下例:
Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());} }); t1.start();我們需要自己創建、啟動Thread對象。
2. 使用Executors執行線程
一些已有的執行器可以幫我們管理Thread對象。你無需自己創建與控制Thread對象。
比如,你不用在代碼中編寫new Thread或者thread1.start()也一樣可以使用多線程。如下例:
ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) {//5個任務exec.submit(new Runnable() {@Overridepublic void run() { System.out.println(Thread.currentThread().getName()+" doing task");}}); } exec.shutdown(); //關閉線程池輸出如下:
pool-1-thread-2 doing task pool-1-thread-1 doing task pool-1-thread-3 doing task pool-1-thread-4 doing task pool-1-thread-5 doing task從輸出我們可以看到,exec使用了線程池1中的5個線程做了這幾個任務。
這個例子中exec這個Executor負責管理任務,所謂的任務在這里就是實現了Runnable接口的匿名內部類。
至于要使用幾個線程,什么時候啟動這些線程,是用線程池還是用單個線程來完成這些任務,我們無需操心。完全由exec這個執行器來負責。
在這里exec(newCachedThreadPool)指向是一個可以根據需求創建新線程的線程池。
2.1?Executors工具類
Executors相當于執行器的工廠類,包含各種常用執行器的工廠方法,可以直接創建常用的執行器。幾種常用的執行器(靜態方法)如下:
Executors.newCachedThreadPool();??????? //創建一個緩沖池,緩沖池容量大小為Integer.MAX_VALUE
Executors.newFixedThreadPool(int);??? //創建固定容量大小的緩沖池
Executors.newSingleThreadExecutor();?? //創建容量為1的緩沖池
Executors.newScheduledThreadPool(corePoolSize); ? ? ? // 創建一個定長線程池,支持定時及周期性任務執行。
在java doc中,并不提倡我們直接使用ThreadPoolExecutor,而是經常使用Executors類中提供的幾個靜態方法來創建線程池。
從下面它們的具體實現來看,它們實際上也是調用了ThreadPoolExecutor,只不過參數都已配置好了。
2.1.1 newCachedThreadPool()
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程(線程池中曾經創建的線程,在完成某個任務后也許會被用來完成另外一項任務),若無可回收,則新建線程。
實現原理:將corePoolSize設置為0,將maximumPoolSize設置為Integer.MAX_VALUE,
使用的是沒有容量的SynchronousQueue(無界),但其maximumPoolSize是無界的,也就是說來了任務就創建線程運行,并且當主線程提交任務的速度高于maximumPoolSize中線程處理任務的速度時CachedThreadPool將會不斷的創建新的線程。
適用于執行很多的短期異步任務的小程序,或者是負載較輕的服務器。在極端情況下,CachedThreadPool會因為創建過多線程而耗盡CPU和內存資源。
60L:當線程空閑超過60秒,就銷毀線程。
2.1.2 newFixedThreadPool(int nThreads)
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }這個創建的線程池corePoolSize和maximum PoolSize值是相等的,都為nThreads。
keepAliveTime=0L:線程一空閑,就立即銷毀。
它使用的LinkedBlockingQueue(無界隊列)。使用該隊列作為工作隊列會對線程池產生如下影響:
(1)當前線程池中的線程數量達到corePoolSize后,新的任務將在無界隊列中等待;
(2)由于我們使用的是無界隊列,所以參數maximumPoolSize和keepAliveTime無效;
(3)由于使用無界隊列,運行中的FixedThreadPool不會拒絕任務(當然此時是未執行shutdown和shutdownNow方法)。
所以不會去調用RejectExecutionHandler的rejectExecution方法拋出異常。
創建一個定長線程池(最大線程數是nThreads),可控制線程最大并發數,超出的線程會在隊列LinkedBlockingQueue中等待。適用于為了滿足資源管理要求,而需要限制當前線程數量的應用場景。
線程在執行完自己當前任務后,會在循環中反復從LinkedBlockingQueue獲取任務來執行。
2.1.3 newSingleThreadExecutor()
public static ExecutorService newSingleThreadPool() {return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。這種特點可以被用來處理共享資源的問題而不需要考慮同步的問題。
適用于需要保證順序地執行各個任務,并且在任意時間點,不會有多個線程是活動的應用場景。
它使用的LinkedBlockingQueue(無界隊列)。
2.1.4 newSingleThreadScheduledExector()?
只包含一個線程的定時及周期線程池。即使任務再多,也只用1個線程完成任務。
2.1.5 newScheduledThreadPool ()
創建一個定長線程池,支持定時及周期性任務執行。
適用于多個后臺線程執行周期任務,同時為了滿足資源管理的需求而限制后臺線程的數量的應用場景。
2.1.6 表格對比
| SynchronousQueue 無界 | 0 | Integer.MAX_VALUE | 很多的短期異步任務的小程序,或者是負載較輕的服務器。 |
| LinkedBlockingQueue 無界 | =nThreads | =nThreads | 為了滿足資源管理要求,而需要限制當前線程數量 |
| LinkedBlockingQueue 無界 | 1 | 1 | 于需要保證順序地執行各個任務,并且在任意時間點,不會有多個線程是活動 |
| ? | 一個線程 | ? | 定時及周期線程池 |
| ? | 定長線程池 | ? | 多個后臺線程執行周期任務,限制后臺線程的數量 |
總結
- 上一篇: 线程安全、守护线程、join()
- 下一篇: 优化查询、访问量大时的优化