1 線程池的實現原理及基本類結構
合理利用線程池能夠帶來三個好處。
- 降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的消耗。
- 提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
- 提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。
Executor線程池框架的最大優點是把任務的提交和執行解耦。客戶端將要執行的任務封裝成Task,然後提交即可。而Task如何執行客戶端則是透明的。具體點講,提交一個Callable對象給ExecutorService(如最常用的線程池ThreadPoolExecutor),將得到一個Future對象,調用Future對象的get方法等待執行結果。
下圖是線程池所涉及到的所有類的結構圖(右鍵查看大圖),先從整體把握下:
圖1 線程池實現原理類結構圖
上面這個圖是很複雜的,涉及到了線程池內部實現原理的所有類,不利於我們理解線程池如何使用。我們先從客戶端的角度出發,看看客戶端使用線程池所涉及到的類結構圖:
圖2 線程池使用的基本類結構圖
從圖一可知,實際的線程池類是實現ExecutorService接口的類,有ThreadPoolExecutor、ForkJoinPool和ScheduledThreadPoolExecutor。下面以常用的ThreadPoolExecutor爲例講解。
2 線程池實現步驟
2.1 線程池的創建
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ThreadPoolExecutor</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> corePoolSize, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maximumPoolSize, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
參數說明:
- corePoolSize(線程池的基本線程數): the number of threads to keep in the pool, even if they are idle, unless
allowCoreThreadTimeOut
is set.當提交一個任務到線程池時,線程池會創建一個線程來執行任務,即使其他空閒的基本線程能夠執行新任務也會創建線程,等到需要執行的任務數大於線程池基本大小時就不再創建。如果調用了線程池的prestartAllCoreThreads
方法,線程池會提前創建並啓動所有基本線程。 - maximumPoolSize(線程池最大線程數): the maximum number of threads to allow in the pool.線程池允許創建的最大線程數。如果任務隊列滿了,並且已創建的線程數小於最大線程數,則線程池會再創建新的線程執行任務。值得注意的是如果使用了無界的任務隊列這個參數就沒什麼效果。
- keepAliveTime(線程活動保持時間):when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.線程池的工作線程空閒後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高線程的利用率。
- TimeUnit(線程活動保持時間的單位):the time unit for the keepAliveTime argument. 可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
- workQueue(任務隊列):the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.用於保存等待執行的任務的阻塞隊列。 可以選擇以下幾個阻塞隊列。
ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。
LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列。
SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。
PriorityBlockingQueue:一個具有優先級的無限阻塞隊列。 - ThreadFactory:用於設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字。
- RejectedExecutionHandler(飽和策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略默認情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略。
AbortPolicy:直接拋出異常。
CallerRunsPolicy:只用調用者所在線程來運行任務。
DiscardOldestPolicy:丟棄隊列裏最近的一個任務,並執行當前任務。
DiscardPolicy:不處理,丟棄掉。
當然也可以根據應用場景需要來實現RejectedExecutionHandler接口自定義策略。如記錄日誌或持久化不能處理的任務。
由此可見,創建一個線程所需的參數很多,線程池爲我們提供了類Executors的靜態工廠方法以創建不同類型的線程池。
- newFixedThreadPool
可以生成固定大小的線程池;
- newCachedThreadPool
可以生成一個無界、可以自動回收的線程池;
- newSingleThreadScheduledExecutor
可以生成一個單個線程的線程池;
- newScheduledThreadPool
還可以生成支持週期任務的線程池。
2.2 向線程池提交任務
有兩種方式提交任務:
1.使用void execute(Runnable command)
方法提交任務
execute方法返回類型爲void,所以沒有辦法判斷任務是否被線程池執行成功。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Runnable task = new Runnable() { @Override public void run() { System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Task is running by "</span> + Thread<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.currentThread</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getName</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池正在執行的線程數:"</span> + threadPoolExecutor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getActiveCount</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } }<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.execute</span>(task)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
2.使用submit
方法提交任務 Future<?> submit(Runnable task);
、<T>
Future<T> submit(Runnable task, T result);
和 Future<T> submit(Callable<T> task);
會返回一個Future,可以通過這個future來判斷任務是否執行成功,通過future的get方法來獲取返回值,get方法會阻塞直到任務完成,而使用get(long
timeout, TimeUnit unit)方法則會阻塞一段時間後立即返回,這時有可能任務沒有執行完。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Future<?> future = threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.submit</span>(task)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> try { Object result = future<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.get</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"任務是否完成:"</span> + future<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isDone</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"返回的結果爲:"</span> + result)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } catch (InterruptedException | ExecutionException e) { e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.printStackTrace</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } finally { // 關閉線程池 threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.shutdown</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
2.3 線程池關閉
shutdown()
方法:這個方法會平滑地關閉ExecutorService,當我們調用這個方法時,ExecutorService停止接受任何新的任務且等待已經提交的任務執行完成(已經提交的任務會分兩類:一類是已經在執行的,另一類是還沒有開始執行的),當所有已經提交的任務執行完畢後將會關閉ExecutorService。awaitTermination(long timeout, TimeUnit unit)
方法:這個方法有兩個參數,一個是timeout即超時時間,另一個是unit即時間單位。這個方法會使當前關閉線程池的線程等待timeout時長,當超過timeout時間後,則去監測ExecutorService是否已經關閉,若關閉則返回true,否則返回false。一般情況下會和shutdown方法組合使用。shutdownNow()
方法:這個方法會強制關閉ExecutorService,它將取消所有運行中的任務和在工作隊列中等待的任務,這個方法返回一個List列表,列表中返回的是等待在工作隊列中的任務。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">// <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4.</span> 關閉線程池 threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.shutdown</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> // hreadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.shutdownNow</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池是否關閉:"</span> + threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isShutdown</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> try { //當前線程阻塞<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>ms後,去檢測線程池是否終止,終止則返回true while(!threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.awaitTermination</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>, TimeUnit<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.MILLISECONDS</span>)) { System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"檢測線程池是否終止:"</span> + threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isTerminated</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } } catch (InterruptedException e) { e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.printStackTrace</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池是否終止:"</span> + threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isTerminated</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>
完整案例:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">package <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.markliu</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.concurrent</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.threadpool</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> import java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.util</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.concurrent</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ExecutionException</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> import java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.util</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.concurrent</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ExecutorService</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> import java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.util</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.concurrent</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Executors</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> import java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.util</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.concurrent</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Future</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> import java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.util</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.concurrent</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ThreadPoolExecutor</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> import java<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.util</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.concurrent</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.TimeUnit</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> public class ThreadPoolDemo1 { public static void main(String[] args) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * 1. 創建線程池 * * 創建一個固定線程數目的線程池。corePoolSize = maximumPoolSize = 5 * 即線程池的基本線程數和最大線程數相等。 * 相當於: * new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); */</span> ExecutorService threadPool = Executors<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.newFixedThreadPool</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * 2. 封裝任務並提交給線程池 */</span> ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) threadPool<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> Runnable task = new Runnable() { @Override public void run() { System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Task is running by "</span> + Thread<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.currentThread</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getName</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池正在執行的線程數:"</span> + threadPoolExecutor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getActiveCount</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> try { TimeUnit<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SECONDS</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sleep</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } catch (InterruptedException e) { e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.printStackTrace</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } } }<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * Starts all core threads, causing them to idly wait for work. * This overrides the default policy of starting core threads * only when new tasks are executed. */</span> int count = threadPoolExecutor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.prestartAllCoreThreads</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"開啓的所有core線程數:"</span> + count)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池當前線程數:"</span> + threadPoolExecutor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getPoolSize</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池的core number of threads:"</span> + threadPoolExecutor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getCorePoolSize</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池中的最大線程數:"</span> + threadPoolExecutor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getLargestPoolSize</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3.</span> 執行,獲取返回結果 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * execute方式提交任務 */</span> // threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.execute</span>(task)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * submit方式提交任務 */</span> Future<?> future = threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.submit</span>(task)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> try { // 阻塞,等待線程執行完成,並獲得結果 Object result = future<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.get</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"任務是否完成:"</span> + future<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isDone</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"返回的結果爲:"</span> + result)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } catch (InterruptedException | ExecutionException e) { e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.printStackTrace</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } finally { System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池中已經執行完的任務數:"</span> + threadPoolExecutor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getCompletedTaskCount</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4.</span> 關閉線程池 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * shutdown方法平滑地關閉線程池,將線程池的狀態設爲:SHUTDOWN * 停止接受任何新的任務且等待已經提交的任務執行完成,當所有已經 * 提交的任務執行完畢後將會關閉線程池 */</span> threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.shutdown</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * shutdownNow方法強制關閉線程池,將線程池狀態設置爲:STOP * 取消所有運行中的任務和在工作隊列中等待的任務,並返回所有未執行的任務List */</span> // hreadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.shutdownNow</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池是否關閉:"</span> + threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isShutdown</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> try { //當前線程阻塞<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>ms後,去檢測線程池是否終止,終止則返回true while(!threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.awaitTermination</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>, TimeUnit<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.MILLISECONDS</span>)) { System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"檢測線程池是否終止:"</span> + threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isTerminated</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } } catch (InterruptedException e) { e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.printStackTrace</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } System<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.out</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.println</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程池是否終止:"</span> + threadPool<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.isTerminated</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li></ul>
3 線程池的執行流程分析
線程池的主要工作流程如下圖:
當提交一個新任務到線程池時,線程池的處理流程如下:
- 首先線程池判斷“基本線程池”(corePoolSize)是否已滿?沒滿,創建一個工作線程來執行任務。滿了,則進入下個流程。
- 其次線程池判斷工作隊列(workQueue)是否已滿?沒滿,則將新提交的任務存儲在工作隊列裏。滿了,則進入下個流程。
- 最後線程池判斷整個線程池的線程數是否已超過maximumPoolSize?沒滿,則創建一個新的工作線程來執行任務,滿了,則交給拒絕策略來處理這個任務。
(我的理解:提交任務—>如果線程數未達到corePoolSize,則創建線程執行任務—>如果達到corePoolSize,仍讓提交了任務,則會有任務等待,所以將任務保存在任務隊列中,直到任務隊列workQueue已滿—>如果workQueue已滿,仍然有任務提交,但未達到最大線程數,則繼續創建線程執行任務,直到線程數達到maximumPoolSize,如果達到了maximumPoolSize,則根據飽和策略拒絕該任務。這也就解釋了爲什麼有了corePoolSize還有maximumPoolSize的原因。)
關於線程池的工作原理後期從源代碼分析。
4 線程池的監控
通過線程池提供的參數進行監控:
- taskCount:線程池需要執行的任務數量。
- completedTaskCount:線程池在運行過程中已完成的任務數量。小於或等於taskCount。
- largestPoolSize:線程池曾經創建過的最大線程數量。通過這個數據可以知道線程池是否滿過。如等於線程池的最大大小,則表示線程池曾經滿了。
- getPoolSize:線程池的線程數量。如果線程池不銷燬的話,池裏的線程不會自動銷燬,所以這個大小隻增不減
- getActiveCount:獲取活動的線程數。
通過繼承線程池並重寫線程池的beforeExecute,afterExecute和terminated方法,可以在任務執行前,執行後和線程池關閉前幹一些事情。如監控任務的平均執行時間,最大執行時間和最小執行時間等。這幾個方法在線程池裏是空方法。
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 給定的Thread執行Runnable之前調用此方法 * *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> t the thread that will run task {@code r} *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> r the task that will be executed */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">beforeExecute</span>(Thread t, Runnable r) { } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 給定的Runnable完成後執行此方法 * This method is invoked by the thread that executed the task. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> r the runnable that has completed *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> t the exception that caused termination, or null if * execution completed normally */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">afterExecute</span>(Runnable r, Throwable t) { } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 當Executor終止時調用此方法. * 注意:方法中子類應調用super.terminated() */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">terminated</span>() { }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
例如:
<code class="hljs php has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ExtendedExecutor</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ThreadPoolExecutor</span> {</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (t == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && r <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">instanceof</span> Future<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><?</span>>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { Object result = ((Future<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"><?</span>>) r).get(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (CancellationException ce) { t = ce; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (ExecutionException ee) { t = ee.getCause(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InterruptedException ie) { Thread.currentThread().interrupt(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ignore/reset</span> } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (t != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) System.out.println(t); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li></li></ul>