[改善Java代码]适时选择不同的线程池来实现
Java的線程池實現從最根本上來說只有兩個:ThreadPoolExecutor類和ScheduledThreadPoolExecutor類,這兩個類還是父子關系,但是Java為了簡化并行計算,還提供了一個Executors的靜態類,它可以直接生成多種不同的線程池執行器,比如單線程執行器,帶緩沖功能的執行器等.但歸根結底還是使ThreadPoolExecutor類或ScheduledThreadPoolExecutor類的封裝類.
?為了了解這些個執行器,看ThreadPoolExecutor類,其中它復雜的構造函數可以很好的解釋該線程池的作用:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}?
上面第二個是ThreadPoolExecutor最完整的構造函數,其他的構造函數都是引用該構造函數實現的.
1.corePoolSize:最小線程數
線程池啟動后,池中保持線程的最小數量,需要說明的是線程數量是逐步到達corePoolSize值的,例如corePoolSize被設置為10,而任務數量只有5,則線程池中最多啟動5個線程,而不是一次性啟動10個線程.
2.maximumPoolSize:最大線程數量
這是池中能夠榮達的最大線程數,如果超出,則使用RejectedExecutionHandler拒絕策略處理.
3.keepAliveTime:線程最大生命期
這個生命周期有兩個約束條件:一是該參數針對的是超過corePoolSize數量的線程,二是處于非運行狀態的線程.
如果corePoolSize為10,maximumPoolSize為20,此時線程池中有15個線程在運行,一段時間后,其中有3個線程處于等待狀態的時間超過了keepAliveTime指定的時間,則結束這3個線程,
此時線程中則還有12個線程正在運行.
4.unit:時間單位
這是keepAliveTime的時間單位,可以是納秒,毫秒,秒,分鐘等選項
5.workQueue:任務隊列
當線程池中的線程都處于運行狀態,而此時任務數量繼續增加,則需要有一個容器來容納這些任務,這就是任務隊列.
6.threadFactory:線程工廠
定義如何啟動一個線程,可以設置線程名稱,并且可以確認是否是后臺線程等.
7.handler:拒絕任務處理器
由于超出線程數量和任務隊列容量而對繼續增加的任務進行處理的程序.
?
Executors提供的幾個創建線程池的便捷方法:
1.newSingleThreadExecutors:單線程池
顧名思義就是一個池中就只有一個線程,該線程用不超時,而且由于是一個線程,當有多個任務需要處理時,會將它們放置到一個無界阻塞隊列中逐個處理.
1 /** 2 * Creates an Executor that uses a single worker thread operating 3 * off an unbounded queue. (Note however that if this single 4 * thread terminates due to a failure during execution prior to 5 * shutdown, a new one will take its place if needed to execute 6 * subsequent tasks.) Tasks are guaranteed to execute 7 * sequentially, and no more than one task will be active at any 8 * given time. Unlike the otherwise equivalent 9 * <tt>newFixedThreadPool(1)</tt> the returned executor is 10 * guaranteed not to be reconfigurable to use additional threads. 11 * 12 * @return the newly created single-threaded Executor 13 */ 14 public static ExecutorService newSingleThreadExecutor() { 15 return new FinalizableDelegatedExecutorService 16 (new ThreadPoolExecutor(1, 1, 17 0L, TimeUnit.MILLISECONDS, 18 new LinkedBlockingQueue<Runnable>())); 19 }?
改方法的使用代碼如下:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;public class Client {public static void main(String[] args) throws Exception {//創建單線程執行器ExecutorService es = Executors.newSingleThreadExecutor();//執行一個任務Future<String> future = es.submit(new Callable<String>() {public String call() throws Exception {return "";}});//獲得任務執行后的返回值System.out.println("返回值:" + future.get());//關閉執行器 es.shutdown();} }?
2.newCachedThreadPool:緩沖功能的線程池
建立了一個線程池,該線程池的數量是沒有限制的(不能超過Integer的最大值),新增一個任務就有一個線程處理,或者復用之前的空閑線程,或者啟動一個新的線程.但是一旦一個線程在60秒內一直是處于等待狀態時,也就是1分鐘沒有事情可做,就會被終止,源代碼:
/*** Creates a thread pool that creates new threads as needed, but* will reuse previously constructed threads when they are* available. These pools will typically improve the performance* of programs that execute many short-lived asynchronous tasks.* Calls to <tt>execute</tt> will reuse previously constructed* threads if available. If no existing thread is available, a new* thread will be created and added to the pool. Threads that have* not been used for sixty seconds are terminated and removed from* the cache. Thus, a pool that remains idle for long enough will* not consume any resources. Note that pools with similar* properties but different details (for example, timeout parameters)* may be created using {@link ThreadPoolExecutor} constructors.** @return the newly created thread pool*/public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}?
這里需要說明的是,任務隊列使用了同步阻塞隊列,這意味著向隊列中加入一個元素,即可喚醒一個線程(新創建的線程或復用池中空閑線程)來處理.這種隊列已經沒有隊列深度的概念了.
3.newFixedThreadPool:固定線程數量的線程池
在初始化時已經決定了線程的最大數量,若任務添加的能力超出線程處理能力,則建立阻塞隊列容納多余的任務,源代碼:
/*** Creates a thread pool that reuses a fixed number of threads* operating off a shared unbounded queue. At any point, at most* <tt>nThreads</tt> threads will be active processing tasks.* If additional tasks are submitted when all threads are active,* they will wait in the queue until a thread is available.* If any thread terminates due to a failure during execution* prior to shutdown, a new one will take its place if needed to* execute subsequent tasks. The threads in the pool will exist* until it is explicitly {@link ExecutorService#shutdown shutdown}.** @param nThreads the number of threads in the pool* @return the newly created thread pool* @throws IllegalArgumentException if {@code nThreads <= 0}*/public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}?
上面返回是一個ThreadPoolExector,它的corePoolSize和maximumPoolSize是相等的,也就是說最大線程數是nThreads.
如果任務增長非常快,超過了LinkedBlockingQueue的最大容量(Integer最大值),那此時會如何處理呢?
會按照ThreadPoolExecutor默認的拒絕策略(默認是DiscardPolicy,直接丟棄)來處理.
以上三種線程池執行器都是ThreadPoolExecutor的簡化版,目的是幫助開發人員屏蔽過多的線程細節,簡化多線程開發.
可以這樣比喻:newSingleTheadExecutor,newCachedThreadPool,newFixedThreadPool是線程池的簡化版,而ThreadPoolExecutor是旗艦版.
?
轉載于:https://www.cnblogs.com/DreamDrive/p/5624024.html
總結
以上是生活随笔為你收集整理的[改善Java代码]适时选择不同的线程池来实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 上配置swoole
- 下一篇: JVM 内存初学 (堆(heap)、栈(