java封裝的幾個線程池介紹
FixedThreadPool
FixedThreadPool並不是一個類,它是由Executors工具類建立出來的一個固定線程數的一個ThreadPoolEexcutor的對象,有2種實現方式。
Executors.newFixedThreadPool(3);//固定3個線程數Executors.newFixedThreadPool(3, Executors.defaultThreadFactory());
我們來看下newFixedThreadPool()的內部實現吧
public static ExecutorService newFixedThreadPool(int nThreads) { //這裡可以看出,返回的就是一個TreadPoolExecutor對象,不過這個對象的核心線程數和最大線程數相等 return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());}public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), //相比上面的方法,就是多了threadFactory參數 threadFactory);}
newFixedThreadPool()分析
這裡就用一個參數的方法來分析。 corePoolSize和maxPoolSize都是參數nThreads:線程池中都是核心線程且是nThraeds個時,沒有非核心線程。 非背景工作執行緒的存活時間是0:當核心線程執行完隊列中的任務時,如果隊列中沒有任務,這時核心線程死亡。極大程度的節約了系統資源。 使用的隊列預設最大值是Integer.MAX_VALUE:該隊列長度是int最大值,相當於無限大了,這樣不管你有多少任務,都能夠儲存在隊列裡面,等待核心線程去執行。
線程池中執行任務大致分為4個階段。
1.任務數小於核心線程數,如果在執行新任務,則建立核心線程去執行任務。
2.當核心線程都在執行任務時,未執行的任務且小於隊列長度,這是任務會儲存於隊列中。
3.當核心線程都在執行任務,且未執行任務數大於隊列長度,這是非核心線程會執行新的任務。
4.當核心線程都在執行任務,且未執行任務數大於隊列長度,且非核心線程也在執行任務,這是會採用飽和策略。
newFixedPoolExecutor()建立出來的線程池,不會有第3階段。
FixedPoolExecutor的使用情境:
FixedThreadPool適用於為了滿足資源管理的需求,而需要限制當前線程數量的應用情境,它適用於負載比較重的伺服器。 SingleThreadPool
SingleThreadPool是只有一個線程的線程池,內部實現和FixedThreadPool一樣,不過就是線程數有區別。
SingleThreadPool的調用方法
Executors.newSingleThreadExecutor();Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
SingleThreadPool的內部實現
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService( new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));}public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory));}
我們看到new FinalizableDelegatedExecutorService()對象包裹了一個ThreadPoolExecutor對象,這個ThreadPoolExecutor對象其實就是一個線程的FixedThreadPool,而FinalizableDelegatedExecutorService類就是對ThreadPoolExecutor在封裝了一層。
所以我們也可以簡單的理解為SingleThreadPool是只有一個線程的FixedThreadPool。 CachedThreadPool
CachedThreadPool的調用方法
Executors.newCachedThreadPool();Executors.newCachedThreadPool(Executors.defaultThreadFactory());
CachedThreadPool的內部實現
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0,Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());}public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory);}
newCachedThreadPool()中的ThreadPoolExecutor對象參數分析 corePoolSize核心線程數為0 maxPoolSize最大線程數為Integer.MAX_VALUE。 keepAliveTime:非背景工作執行緒存活時間60秒 workQueue:隊列使用的SynchronousQueue(SynchronousQueue是一個沒有容量的隊列)。
通過參數我們可以知道,沒有核心線程數,那麼就不會走線程池的第一個階段,SynchronousQueue隊列是一個沒有容量的阻塞隊列。每個插入操作必須等待另一 個線程的對應移除操作。
下面看下CachedThreadPool的execute()方法的執行示意圖:
1.execute()首先執行SynchronousQueue.offer(Runnable r)。如果的當前maxPool中有空閑線程,會執行SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS),那麼主線程(調用execute()的線程)執行offer操作與空閑線程執行的poll操作配對成功。主線程把任務交給空閑線程執行,execute()方法執行完成。
2.當maxPool為空白,或者maxPool中當前沒有空閑線程時,將沒有線程執行SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)。這種情況下,步驟1失敗。此時CachedThreadPool會建立一個新線程執行任務,execute()執行完成。
3.在步驟2中,新建立的線程將任務執行完後,會執行SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)。這個poll操作會讓空閑線程最多在SynchronousQueue中等待60秒,如果60秒鐘內主線程提交了一個新任務(主線程執行步驟1),那麼這個空閑線程將執行主線程提交的新任務;否則,這個空閑線程將終止。由於空閑60秒的空閑線程會被終止,因此長時間保持閒置CachedThreadPool不會使用任何資源。
CachedThreadPool是大小無界的線程池,適用於執行很的短期非同步任務的小程式,或者是負載較輕的伺服器。 ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor是ThreadPoolExecutor的子類。
ScheduledThreadPoolEexcutor的調用有4中形式
Executors.newScheduledThreadPool(3);Executors.newScheduledThreadPool(3, Executors.defaultThreadFactory());new ScheduledThreadPoolExecutor(3);new ScheduledThreadPoolExecutor(3, Executors.defaultThreadFactory());
其實Executors.newScheduledThreadPool(3)方法的內部實現也是直接建立一個對象,如:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize);}public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1, threadFactory));}
那我們接下來看下ScheduledThreadPoolExecutor()的構造方法實現
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue());}public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue(), threadFactory);}
從構造方法中可以知道,其實ScheduledThreadPoolExecutor調用的是父類中的構造方法,也就是ThreadPoolExecutor中的構造。那麼我們來說說傳入的參數: corePoolSize:核心線程數,傳入 預設最大線程數為Integer.MAX_VALUE。 保活時間預設10毫秒,DEFAULT_KEEPALIVE_MILLIS預設10L,單位毫秒。 使用的隊列是DelayedWorkQueue,DelayedWorkQueue是一個無界限的隊列,當添加的任務大於隊列時,會從新增加隊列的長度。同時DelayedWorkQueue還有著一套按逾時時間升序排序的演算法,遵循”左結點比右節點小(下次執行的時間更短)的原則。具體細節在下一章解釋。
通過構造我們可以知道,ScheduledThreadPoolExecutor和ThreadPoolExecutor並沒太多的區別,最大的區別就是隊列的不同。因為DelayedWorkQueue的長度具有增長型和按逾時時間升序排序演算法,使得ScheduledThreadPoolExecutor具有延時執行任務的特性。
因為DelayedWorkQueue是屬於無界隊列,那麼最大線程數設定Integer.MAX_VALUE就沒有使用到。
ScheduledThreadPoolExecutor的執行方法
因為ScheduledThreadPoolExecutor繼承自ThreadPoolExecutor,所以會有execute()和submit(),這裡不介紹這2個方法。
ScheduledThreadPoolExecutor除了繼承ThreadPoolExecutor,還實現了ScheduledExecutorService介面
ScheduledExecutorService介面方法
//建立任務並在給定延遲時間後執行public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);//同上,只不過參數是Callablepublic <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);/** * 參數initialDelay:表示第一次延時的時間 * 參數period:表示任務執行開始後距下一個任務開始執行的時間間隔 */public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);/** * 參數initialDelay:表示第一次延時的時間 * 參數period:表示任務執行結束後距下一個任務開始執行的時間間隔 */ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
schedule()方法實現代碼:
public ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); //decorateTask()的第2個參數,就是傳回值,也就是即將順延強制的任務對象 RunnableScheduledFuture<Void> t = decorateTask(command,new ScheduledFutureTask<Void>(command, null,triggerTime(delay, unit),sequencer.getAndIncrement())); delayedExecute(t);//順延強制這個任務 return t;}//decorateTask()實現代碼protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) { return task;}
ScheduledThreadPoolExecutor的執行方法非常類似Timer定時器。
ScheduledThreadPoolExecutor的簡單使用 schedule()的使用
public class Test { public static void main(String[] args) { ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3); System.out.println("任務執行前時間:" + System.currentTimeMillis());//任務執行前時間:1496847975977 scheduledThreadPoolExecutor.schedule(new Runnable() { @Override public void run() { System.out.println("任務執行時間:" + System.currentTimeMillis());//任務執行時間:1496847976993 } }, 1000, TimeUnit.MILLISECONDS); }} scheduleAtFixedRate()的使用
public class Test { public static void main(String[] args) { ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3); System.out.println("任務執行前時間:" + System.currentTimeMillis()); scheduledThreadPoolExecutor.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("任務執行時間:" + System.currentTimeMillis()); try { Thread.sleep(1000);//這個是為了區別和下一個方法 } catch (InterruptedException e) { e.printStackTrace(); } } }, 1000, 5000, TimeUnit.MILLISECONDS); }}控制台列印結果:任務執行前時間:1496848166272任務執行時間:1496848167285 //第一次執行,任務延遲1秒執行任務執行時間:1496848172281 //每隔5秒後執行任務任務執行時間:1496848177280任務執行時間:1496848182282任務執行時間:1496848187282 scheduleWithFixedDelay()的使用
public class Test { public static void main(String[] args) { ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3); System.out.println("任務執行前時間:" + System.currentTimeMillis());//任務執行前時間:1496847975977 scheduledThreadPoolExecutor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { System.out.println("任務執行時間:" + System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }, 1000, 5000, TimeUnit.MILLISECONDS); }}列印結果:任務執行前時間:1496848595162任務執行時間:1496848596181 //第一次執行延時任務,延遲1秒任務執行時間:1496848602188 //第2次執行任務,延遲大約6秒(5秒是延遲時間,1秒是任務執行的消耗時間)任務執行時間:1496848608204任務執行時間:1496848614211任務執行時間:1496848620231任務執行時間:1496848626256
ScheduledThreadPoolExecutor停止方法 shutdown() shutdownNow()
這兩個方法在將線程池ThreadPoolExecutor的時候介紹過。 SingleThreadScheduledExecutor
SingleThreadScheduledExecutor和ScheduledThreadPoolExecutor一樣具有延時執行任務的特點。SingleThreadScheduledExecutor的內部實現就是ScheduledThreadPoolExecutor,只不過只有一個核心線程(雖然有最大線程數,但是隊列的無邊界的,所以除核心線程外,其他線程不會執行任務)。
SingleThreadScheduledExecutor的調用
Executors.newSingleThreadScheduledExecutor();Executors.newSingleThreadScheduledExecutor(Executors.defaultThreadFactory());
SingleThreadScheduledExecutor的內部實現
public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1));}public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1, threadFactory));}