Java併發編程指南專欄html
分佈式系統的經典基礎理論java
[TOC]編程
本節思惟導圖:
小程序
思惟導圖源文件+思惟導圖軟件關注微信公衆號:「Java面試通關手冊」 回覆關鍵字:「Java多線程」 免費領取。服務器
線程池提供了一種限制和管理資源(包括執行一個任務)。 每一個線程池還維護一些基本統計信息,例如已完成任務的數量。
這裏借用《Java併發編程的藝術》提到的來講一下使用線程池的好處:微信
Executor 框架是Java5以後引進的,在Java 5以後,經過 Executor 來啓動線程比使用 Thread 的 start 方法更好,除了更易管理,效率更好(用線程池實現,節約開銷)外,還有關鍵的一點:有助於避免 this 逃逸問題。多線程
補充:this逃逸是指在構造函數返回以前其餘線程就持有該對象的引用. 調用還沒有構造徹底的對象的方法可能引起使人疑惑的錯誤。
執行任務須要實現的Runnable接口或Callable接口。
Runnable接口或Callable接口實現類均可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor執行。架構
二者的區別:
Runnable接口不會返回結果可是 Callable接口能夠返回結果。後面介紹 Executors類的一些方法的時候會介紹到二者的相互轉換。
以下圖所示,包括任務執行機制的核心接口Executor ,以及繼承自Executor 接口的ExecutorService接口。ScheduledThreadPoolExecutor和ThreadPoolExecutor這兩個關鍵類實現了ExecutorService接口。
注意: 經過查看ScheduledThreadPoolExecutor源代碼咱們發現ScheduledThreadPoolExecutor其實是繼承了ThreadPoolExecutor並實現了ScheduledExecutorService ,而ScheduledExecutorService又實現了ExecutorService,正如咱們下面給出的類關係圖顯示的同樣。
ThreadPoolExecutor類描述:
//AbstractExecutorService實現了ExecutorService接口 public class ThreadPoolExecutor extends AbstractExecutorService
ScheduledThreadPoolExecutor類描述:
//ScheduledExecutorService實現了ExecutorService接口 public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService
Future接口以及Future接口的實現類FutureTask類。
當咱們把Runnable接口或Callable接口的實現類提交(調用submit方法)給ThreadPoolExecutor或ScheduledThreadPoolExecutor時,會返回一個FutureTask對象。
咱們以AbstractExecutorService接口中的一個submit方法爲例子來看看源代碼:
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; }
上面方法調用的newTaskFor方法返回了一個FutureTask對象。
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); }
而後能夠把建立完成的Runnable對象直接交給ExecutorService執行(ExecutorService.execute(Runnable command));或者也能夠把Runnable對象或Callable對象提交給ExecutorService執行(ExecutorService.submit(Runnable task)或ExecutorService.submit(Callable <T> task))。
執行execute()方法和submit()方法的區別是什麼呢?
1) execute()方法用於提交不須要返回值的任務,因此沒法判斷任務是否被線程池執行成功與否;
2) submit()方法用於提交須要返回值的任務。線程池會返回一個future類型的對象,經過這個future對象能夠判斷任務是否執行成功,而且能夠經過future的get()方法來獲取返回值,get()方法會阻塞當前線程直到任務完成,而使用get(long timeout,TimeUnit unit)方法則會阻塞當前線程一段時間後當即返回,這時候有可能任務沒有執行完。
線程池實現類ThreadPoolExecutor是Executor 框架最核心的類,先來看一下這個類中比較重要的四個屬性
咱們看最長的那個,其他三個都是在這個構造方法的基礎上產生(給定某些默認參數的構造方法)
/** * 用給定的初始參數建立一個新的ThreadPoolExecutor。 * @param keepAliveTime 當線程池中的線程數量大於corePoolSize的時候,若是這時沒有新的任務提交, *核心線程外的線程不會當即銷燬,而是會等待,直到等待的時間超過了keepAliveTime; * @param unit keepAliveTime參數的時間單位 * @param workQueue 等待隊列,當任務提交時,若是線程池中的線程數量大於等於corePoolSize的時候,把該任務封裝成一個Worker對象放入等待隊列; * * @param threadFactory 執行者建立新線程時使用的工廠 * @param handler RejectedExecutionHandler類型的變量,表示線程池的飽和策略。 * 若是阻塞隊列滿了而且沒有空閒的線程,這時若是繼續提交任務,就須要採起一種策略處理該任務。 * 線程池提供了4種策略: 1.AbortPolicy:直接拋出異常,這是默認策略; 2.CallerRunsPolicy:用調用者所在的線程來執行任務; 3.DiscardOldestPolicy:丟棄阻塞隊列中靠最前的任務,並執行當前任務; 4.DiscardPolicy:直接丟棄任務; */ 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; }
方式一:經過構造方法實現(官方API文檔並不推薦,因此建議使用第二種方式)
方式二:經過Executor 框架的工具類Executors來實現
咱們能夠建立三種類型的ThreadPoolExecutor:
對應Executors工具類中的方法如圖所示:
FixedThreadPool被稱爲可重用固定線程數的線程池。經過Executors類中的相關源代碼來看一下相關實現:
/** * 建立一個可重用固定數量線程的線程池 *在任什麼時候候至多有n個線程處於活動狀態 *若是在全部線程處於活動狀態時提交其餘任務,則它們將在隊列中等待, *直到線程可用。 若是任何線程在關閉以前的執行期間因爲失敗而終止, *若是須要執行後續任務,則一個新的線程將取代它。池中的線程將一直存在 *知道調用shutdown方法 * @param nThreads 線程池中的線程數 * @param threadFactory 建立新線程時使用的factory * @return 新建立的線程池 * @throws NullPointerException 若是threadFactory爲null * @throws IllegalArgumentException if {@code nThreads <= 0} */ public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
另外還有一個FixedThreadPool的實現方法,和上面的相似,因此這裏很少作闡述:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
從上面源代碼能夠看出新建立的FixedThreadPool的corePoolSize和maximumPoolSize都被設置爲nThreads。
FixedThreadPool的execute()方法運行示意圖(該圖片來源:《Java併發編程的藝術》):
上圖說明:
FixedThreadPool使用無界隊列 LinkedBlockingQueue(隊列的容量爲Intger.MAX_VALUE)做爲線程池的工做隊列會對線程池帶來以下影響:
SingleThreadExecutor是使用單個worker線程的Executor。下面看看SingleThreadExecutor的實現:
/** *建立使用單個worker線程運行無界隊列的Executor *並使用提供的ThreadFactory在須要時建立新線程 * * @param threadFactory 建立新線程時使用的factory * * @return 新建立的單線程Executor * @throws NullPointerException 若是ThreadFactory爲空 */ public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
從上面源代碼能夠看出新建立的SingleThreadExecutor的corePoolSize和maximumPoolSize都被設置爲1.其餘參數和FixedThreadPool相同。SingleThreadExecutor使用無界隊列LinkedBlockingQueue做爲線程池的工做隊列(隊列的容量爲Intger.MAX_VALUE)。SingleThreadExecutor使用無界隊列做爲線程池的工做隊列會對線程池帶來的影響與FixedThreadPool相同。
SingleThreadExecutor的運行示意圖(該圖片來源:《Java併發編程的藝術》):
上圖說明;
CachedThreadPool是一個會根據須要建立新線程的線程池。下面經過源碼來看看 CachedThreadPool的實現:
/** * 建立一個線程池,根據須要建立新線程,但會在先前構建的線程可用時重用它, *並在須要時使用提供的ThreadFactory建立新線程。 * @param threadFactory 建立新線程使用的factory * @return 新建立的線程池 * @throws NullPointerException 若是threadFactory爲空 */ public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
CachedThreadPool的corePoolSize被設置爲空(0),maximumPoolSize被設置爲Integer.MAX.VALUE,即它是無界的,這也就意味着若是主線程提交任務的速度高於maximumPool中線程處理任務的速度時,CachedThreadPool會不斷建立新的線程。極端狀況下,這樣會致使耗盡cpu和內存資源。
CachedThreadPool的execute()方法的執行示意圖(該圖片來源:《Java併發編程的藝術》):
上圖說明:
首先建立一個Runnable接口的實現類(固然也能夠是Callable接口,咱們上面也說了二者的區別是:Runnable接口不會返回結果可是Callable接口能夠返回結果。後面介紹Executors類的一些方法的時候會介紹到二者的相互轉換。)
import java.util.Date; /** * 這是一個簡單的Runnable類,須要大約5秒鐘來執行其任務。 */ public class WorkerThread implements Runnable { private String command; public WorkerThread(String s) { this.command = s; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " Start. Time = " + new Date()); processCommand(); System.out.println(Thread.currentThread().getName() + " End. Time = " + new Date()); } private void processCommand() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public String toString() { return this.command; } }
編寫測試程序,咱們這裏以FixedThreadPool爲例子
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExecutorDemo { public static void main(String[] args) { //建立一個FixedThreadPool對象 ExecutorService executor = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { //建立WorkerThread對象(WorkerThread類實現了Runnable 接口) Runnable worker = new WorkerThread("" + i); //執行Runnable executor.execute(worker); } //終止線程池 executor.shutdown(); while (!executor.isTerminated()) { } System.out.println("Finished all threads"); } }
輸出示例:
pool-1-thread-5 Start. Time = Thu May 31 10:22:52 CST 2018 pool-1-thread-3 Start. Time = Thu May 31 10:22:52 CST 2018 pool-1-thread-2 Start. Time = Thu May 31 10:22:52 CST 2018 pool-1-thread-4 Start. Time = Thu May 31 10:22:52 CST 2018 pool-1-thread-1 Start. Time = Thu May 31 10:22:52 CST 2018 pool-1-thread-4 End. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-1 End. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-2 End. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-5 End. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-3 End. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-5 Start. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-2 Start. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-1 Start. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-4 Start. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-3 Start. Time = Thu May 31 10:22:57 CST 2018 pool-1-thread-5 End. Time = Thu May 31 10:23:02 CST 2018 pool-1-thread-1 End. Time = Thu May 31 10:23:02 CST 2018 pool-1-thread-2 End. Time = Thu May 31 10:23:02 CST 2018 pool-1-thread-3 End. Time = Thu May 31 10:23:02 CST 2018 pool-1-thread-4 End. Time = Thu May 31 10:23:02 CST 2018 Finished all threads
shutdown()方法代表關閉已在Executor上調用,所以不會再向DelayedPool添加任何其餘任務(由ScheduledThreadPoolExecutor類在內部使用)。 可是,已經在隊列中提交的任務將被容許完成。
另外一方面,shutdownNow()方法試圖終止當前正在運行的任務,並中止處理排隊的任務並返回正在等待執行的List。
isShutdown()表示執行程序正在關閉,但並不是全部任務都已完成執行。
另外一方面,isShutdown()表示全部線程都已完成執行。
ScheduledThreadPoolExecutor主要用來在給定的延遲後運行任務,或者按期執行任務。
ScheduledThreadPoolExecutor使用的任務隊列DelayQueue封裝了一個PriorityQueue,PriorityQueue會對隊列中的任務進行排序,執行所需時間短的放在前面先被執行(ScheduledFutureTask的time變量小的先執行),若是執行所需時間相同則先提交的任務將被先執行(ScheduledFutureTask的squenceNumber變量小的先執行)。
ScheduledThreadPoolExecutor和Timer的比較:
綜上,在JDK1.5以後,你沒有理由再使用Timer進行任務調度了。
備註: Quartz是一個由java編寫的任務調度庫,由OpenSymphony組織開源出來。在實際項目開發中使用Quartz的仍是居多,比較推薦使用Quartz。由於Quartz理論上可以同時對上萬個任務進行調度,擁有豐富的功能特性,包括任務調度、任務持久化、可集羣化、插件等等。
ScheduledThreadPoolExecutor的執行主要分爲兩大部分:
ScheduledThreadPoolExecutor爲了實現週期性的執行任務,對ThreadPoolExecutor作了以下修改:
/** * 使用ScheduledExecutorService和ScheduledThreadPoolExecutor實現的java調度程序示例程序。 */ public class ScheduledThreadPoolDemo { public static void main(String[] args) throws InterruptedException { //建立一個ScheduledThreadPoolExecutor對象 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); //計劃在某段時間後運行 System.out.println("Current Time = "+new Date()); for(int i=0; i<3; i++){ Thread.sleep(1000); WorkerThread worker = new WorkerThread("do heavy processing"); //建立並執行在給定延遲後啓用的單次操做。 scheduledThreadPool.schedule(worker, 10, TimeUnit.SECONDS); } //添加一些延遲讓調度程序產生一些線程 Thread.sleep(30000); System.out.println("Current Time = "+new Date()); //關閉線程池 scheduledThreadPool.shutdown(); while(!scheduledThreadPool.isTerminated()){ //等待全部任務完成 } System.out.println("Finished all threads"); } }
運行結果:
Current Time = Wed May 30 17:11:16 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:11:27 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:11:28 CST 2018 pool-1-thread-3 Start. Time = Wed May 30 17:11:29 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:11:32 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:11:33 CST 2018 pool-1-thread-3 End. Time = Wed May 30 17:11:34 CST 2018 Current Time = Wed May 30 17:11:49 CST 2018 Finished all threads
咱們可使用ScheduledExecutorService scheduleAtFixedRate方法來安排任務在初始延遲後運行,而後在給定的時間段內運行。
時間段是從池中第一個線程的開始,所以若是您將period指定爲1秒而且線程運行5秒,那麼只要第一個工做線程完成執行,下一個線程就會開始執行。
for (int i = 0; i < 3; i++) { Thread.sleep(1000); WorkerThread worker = new WorkerThread("do heavy processing"); // schedule task to execute at fixed rate scheduledThreadPool.scheduleAtFixedRate(worker, 0, 10, TimeUnit.SECONDS); }
輸出示例:
Current Time = Wed May 30 17:47:09 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:47:10 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:47:11 CST 2018 pool-1-thread-3 Start. Time = Wed May 30 17:47:12 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:47:15 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:47:16 CST 2018 pool-1-thread-3 End. Time = Wed May 30 17:47:17 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:47:20 CST 2018 pool-1-thread-4 Start. Time = Wed May 30 17:47:21 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:47:22 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:47:25 CST 2018 pool-1-thread-4 End. Time = Wed May 30 17:47:26 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:47:27 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:47:30 CST 2018 pool-1-thread-3 Start. Time = Wed May 30 17:47:31 CST 2018 pool-1-thread-5 Start. Time = Wed May 30 17:47:32 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:47:35 CST 2018 pool-1-thread-3 End. Time = Wed May 30 17:47:36 CST 2018 pool-1-thread-5 End. Time = Wed May 30 17:47:37 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:47:40 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:47:41 CST 2018 Current Time = Wed May 30 17:47:42 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:47:45 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:47:46 CST 2018 Finished all threads Process finished with exit code 0
ScheduledExecutorService scheduleWithFixedDelay方法可用於以初始延遲啓動週期性執行,而後以給定延遲執行。 延遲時間是線程完成執行的時間。
for (int i = 0; i < 3; i++) { Thread.sleep(1000); WorkerThread worker = new WorkerThread("do heavy processing"); scheduledThreadPool.scheduleWithFixedDelay(worker, 0, 1, TimeUnit.SECONDS); }
輸出示例:
Current Time = Wed May 30 17:58:09 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:58:10 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:58:11 CST 2018 pool-1-thread-3 Start. Time = Wed May 30 17:58:12 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:58:15 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:58:16 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:58:16 CST 2018 pool-1-thread-3 End. Time = Wed May 30 17:58:17 CST 2018 pool-1-thread-4 Start. Time = Wed May 30 17:58:17 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:58:18 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:58:21 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:58:22 CST 2018 pool-1-thread-4 End. Time = Wed May 30 17:58:22 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:58:23 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:58:23 CST 2018 pool-1-thread-4 Start. Time = Wed May 30 17:58:24 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:58:27 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:58:28 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:58:28 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:58:29 CST 2018 pool-1-thread-4 End. Time = Wed May 30 17:58:29 CST 2018 pool-1-thread-4 Start. Time = Wed May 30 17:58:30 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:58:33 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:58:34 CST 2018 pool-1-thread-1 Start. Time = Wed May 30 17:58:34 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:58:35 CST 2018 pool-1-thread-4 End. Time = Wed May 30 17:58:35 CST 2018 pool-1-thread-4 Start. Time = Wed May 30 17:58:36 CST 2018 pool-1-thread-1 End. Time = Wed May 30 17:58:39 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:58:40 CST 2018 pool-1-thread-5 Start. Time = Wed May 30 17:58:40 CST 2018 pool-1-thread-4 End. Time = Wed May 30 17:58:41 CST 2018 pool-1-thread-2 Start. Time = Wed May 30 17:58:41 CST 2018 Current Time = Wed May 30 17:58:42 CST 2018 pool-1-thread-5 End. Time = Wed May 30 17:58:45 CST 2018 pool-1-thread-2 End. Time = Wed May 30 17:58:46 CST 2018 Finished all threads
scheduleAtFixedRate(...)將延遲視爲兩個任務開始之間的差別(即按期調用)
scheduleWithFixedDelay(...)將延遲視爲一個任務結束與下一個任務開始之間的差別
scheduleAtFixedRate(): 建立並執行在給定的初始延遲以後,隨後以給定的時間段首先啓用的週期性動做; 那就是執行將在initialDelay以後開始,而後initialDelay+period ,而後是initialDelay + 2 * period ,等等。 若是任務的執行遇到異常,則後續的執行被抑制。 不然,任務將僅經過取消或終止執行人終止。 若是任務執行時間比其週期長,則後續執行可能會遲到,但不會同時執行。
scheduleWithFixedDelay() : 建立並執行在給定的初始延遲以後首先啓用的按期動做,隨後在一個執行的終止和下一個執行的開始之間給定的延遲。 若是任務的執行遇到異常,則後續的執行被抑制。 不然,任務將僅經過取消或終止執行終止。
FixedThreadPool: 適用於爲了知足資源管理需求,而須要限制當前線程數量的應用場景。它適用於負載比較重的服務器;
SingleThreadExecutor: 適用於須要保證順序地執行各個任務而且在任意時間點,不會有多個線程是活動的應用場景。
CachedThreadPool: 適用於執行不少的短時間異步任務的小程序,或者是負載較輕的服務器;
ScheduledThreadPoolExecutor: 適用於須要多個後臺執行週期任務,同時爲了知足資源管理需求而須要限制後臺線程的數量的應用場景,
SingleThreadScheduledExecutor: 適用於須要單個後臺線程執行週期任務,同時保證順序地執行各個任務的應用場景。
本節只是簡單的介紹了一下使用線程池的好處,而後花了大量篇幅介紹Executor 框架。詳細介紹了Executor 框架中ThreadPoolExecutor和ScheduledThreadPoolExecutor,而且經過實例詳細講解了ScheduledThreadPoolExecutor的使用。對於FutureTask 只是粗略帶過,由於篇幅問題,並無深究它的原理,後面的文章會進行補充。這一篇文章只是大概帶你們過一下線程池的基本概覽,深刻講解的地方不是不少,後續會經過源碼深刻研究其中比較重要的一些知識點。
最後,就是這兩週要考試了,會抽點時間出來簡單應付一下學校考試了。而後,就是寫這篇多線程的文章廢了好多好多時間。一直不知從何寫起。
《Java併發編程的藝術》
Java Scheduler ScheduledExecutorService ScheduledThreadPoolExecutor Example
java.util.concurrent.ScheduledThreadPoolExecutor Example
ThreadPoolExecutor – Java Thread Pool Example
我是Snailclimb,一個以架構師爲5年以內目標的小小白。 歡迎關注個人微信公衆號:" Java面試通關手冊"(一個有溫度的微信公衆號,期待與你共同進步~~~堅持原創,分享美文,分享各類Java學習資源)
最後,就是使用阿里雲服務器一段時間後,感受阿里雲真的很不錯,就申請作了阿里雲大使,而後這是個人優惠券地址.