我與狗子的日常5
執行緒池淺析
執行緒池顧名思義就是放執行緒的池子 Thread Pool。
那麼為什麼要有執行緒池呢?有些時候系統需要處理非常多的執行時間很短的請求,如果每一個請求都開啟一個新的執行緒,則系統建立銷燬執行緒的開銷就太大了,甚至在建立和銷燬執行緒的時間比任務的執行時間還長。
使用new Thread() 會有如下缺點:
1.建立和銷燬執行緒耗費大量系統資源;
2.每次new Thread() 缺乏執行緒管理,被稱為野執行緒,而且可以無限制建立,之間相互競爭,會導致過多佔用系統資源導致系統癱瘓。
3.不利於擴充套件,如定期執行,定時執行,執行緒中斷。
執行緒池主要解決了兩個問題:
1.通過重用執行緒,達到減少每個執行緒建立和銷燬的效能開銷。
2.對執行緒進行一些維護,比如定時開始,週期執行,併發控制等。
3.可控制最大併發執行緒數,提高系統資源的使用率,同時避免過多資源競爭。
Executor:JDK1.5引入,內部使用執行緒池機制,在java.util.cocurrent包下,Executor框架包括:執行緒池,Executor,Executors,ExecutorService,CompletionService,Future,Callable,ThreadPoolExecutor等。
Executors:工廠類 建立執行緒池
1.newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
建立一個固定數目的執行緒池,內部維持一個無界的佇列,當所有的執行緒都在處於活動狀態時提交了其他任務,則新任務將在佇列中等待直到執行緒可用。
2.newCachedThreadPool
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
建立一個根據需要建立新執行緒的執行緒池,但在可用時將重新使用以前構造的執行緒。
該執行緒池適用於執行許多短暫非同步任務的程式,呼叫execute會重用以前構造的執行緒,如果沒有可用的執行緒,則會建立新的執行緒,並將該執行緒新增到該池中,未使用60秒的執行緒將被終止並從快取中刪除。因此,長時間保持閒置的池將不會消耗任何資源。
3.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
建立一個使用無界佇列執行單個工作執行緒的執行程式,等效於newFixedThreadPool(1)
4.newScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }
建立一個執行緒池,可以排程命令在給定的延遲之後執行,或定期執行。
scheduleAtFixedRate(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
首次執行在 initialDelay 之後,第二次 執行時間為 initialDelay+delay*1 ….
scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
第一次的執行時間為 當前時間+ initialDelay,第二次為第一次執行結束時間+delay
ExecutorService 的submit() 和 execute()區別:
1.入參不同 submit可以接收Runnable或者Callable ,execute方法只能接收Runnable
2.返回值 submit 有返回值 而 execute沒有返回值
3.submit方便處理Exception Future.get丟擲的異常
Runnable和Callable的區別
Callable介面中的call方法是有返回值的,泛型可任意制定,但是Runnable介面中run方法是沒有返回值的。
ThreadPoolExecutor:JDK提供的Executors工具類中建立的執行緒無法滿足使用場景時,則需要手動配置和調優,則用到該池。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
引數詳解:
corePoolSize:核心執行緒數
maximumPoolSize:最大執行緒數
keepAliveTime:最大空閒時間
BlockingQueue:使用的任務佇列
ArrayBlockingQueue:底層是陣列的定長任務佇列,必須制定長度,可設定是 否公平鎖。預設先進先出
LinkedBlockingQueue:底層為連結串列的可定長任務佇列,不指定長度則為無界, 可設定公平鎖,預設為先進先出
SynchronousQueue:同步的沒有緩衝的任務佇列,只有當執行緒將佇列中的take走之後,才能新加進來任務
defaultHandler:該引數代表的是拒絕策略,預設為AbortPolicy
可以通過設定改變
/**
* ThreadPoolExecutor.AbortPolicy() 丟擲java.util.concurrent.RejectedExecutionException異常
* ThreadPoolExecutor.CallerRunsPolicy() 使用主執行緒跑當前任務
* ThreadPoolExecutor.DiscardOldestPolicy() 拋棄舊的任務
* ThreadPoolExecutor.DiscardPolicy() 拋棄當前的任務
*/