ThreadPoolExecutor邏輯結構和工作方式

構造函數中需要傳入的參數包括corePoolSize、maximumPoolSize、keepAliveTime、timeUnit和workQueue。要明確理解這些參數(和後續將要介紹的參數)的含義,就首先要搞清楚ThreadPoolExecutor線程池的邏輯結構。 
[圖片] 
一定要注意一個概念,即存在於線程池中容器的一定是Thread對象,而不是你要求運行的任務(所以叫線程池而不叫任務池也不叫對象池);你要求運行的任務將被線程池分配給某一個空閒的Thread運行。 
從上圖中,我們可以看到構成線程池的幾個重要元素: 
● 等待隊列:顧名思義,就是你調用線程池對象的submit()方法或者execute()方法,要求線程池運行的任務(這些任務必須實現Runnable接口或者Callable接口)。但是出於某些原因線程池並沒有馬上運行這些任務,而是送入一個隊列等待執行。

● 核心線程:線程池主要用於執行任務的是“核心線程”,“核心線程”的數量是你創建線程時所設置的corePoolSize參數決定的。如果不進行特別的設定,線程池中始終會保持corePoolSize數量的線程數(不包括創建階段)。

● 非核心線程:一旦任務數量過多(由等待隊列的特性決定),線程池將創建“非核心線程”臨時幫助運行任務。你設置的大於corePoolSize參數小於maximumPoolSize參數的部分,就是線程池可以臨時創建的“非核心線程”的最大數量。這種情況下如果某個線程沒有運行任何任務,在等待keepAliveTime時間後,這個線程將會被銷燬,直到線程池的線程數量重新達到corePoolSize。

● maximumPoolSize參數也是當前線程池允許創建的最大線程數量。那麼如果設置的corePoolSize參數和設置的maximumPoolSize參數一致時,線程池在任何情況下都不會回收空閒線程。keepAliveTime和timeUnit也就失去了意義。

● keepAliveTime參數和timeUnit參數也是配合使用的。keepAliveTime參數指明等待時間的量化值,timeUnit指明量化值單位。例如keepAliveTime=1,timeUnit爲TimeUnit.MINUTES,代表空閒線程的回收閥值爲1分鐘。

說完了線程池的邏輯結構,下面我們討論一下線程池是怎樣處理某一個運行任務的。 
1、首先可以通過線程池提供的submit()方法或者execute()方法,要求線程池執行某個任務。線程池收到這個要求執行的任務後,會有幾種處理情況: 
1.1、如果當前線程池中運行的線程數量還沒有達到corePoolSize大小時,線程池會創建一個新的線程運行你的任務,無論之前已經創建的線程是否處於空閒狀態。 
1.2、如果當前線程池中運行的線程數量已經達到設置的corePoolSize大小,線程池會把你的這個任務加入到等待隊列中。直到某一個的線程空閒了,線程池會根據設置的等待隊列規則,從隊列中取出一個新的任務執行。 
1.3、如果根據隊列規則,這個任務無法加入等待隊列。這時線程池就會創建一個“非核心線程”直接運行這個任務。注意,如果這種情況下任務執行成功,那麼當前線程池中的線程數量一定大於corePoolSize。 
1.4、如果這個任務,無法被“核心線程”直接執行,又無法加入等待隊列,又無法創建“非核心線程”直接執行,且你沒有爲線程池設置RejectedExecutionHandler。這時線程池會拋出RejectedExecutionException異常,即線程池拒絕接受這個任務。(實際上拋出RejectedExecutionException異常的操作,是ThreadPoolExecutor線程池中一個默認的RejectedExecutionHandler實現:AbortPolicy,這在後文會提到) 
2、一旦線程池中某個線程完成了任務的執行,它就會試圖到任務等待隊列中拿去下一個等待任務(所有的等待任務都實現了BlockingQueue接口,按照接口字面上的理解,這是一個可阻塞的隊列接口),它會調用等待隊列的poll()方法,並停留在哪裏。 
3、當線程池中的線程超過你設置的corePoolSize參數,說明當前線程池中有所謂的“非核心線程”。那麼當某個線程處理完任務後,如果等待keepAliveTime時間後仍然沒有新的任務分配給它,那麼這個線程將會被回收。線程池回收線程時,對所謂的“核心線程”和“非核心線程”是一視同仁的,直到線程池中線程的數量等於你設置的corePoolSize參數時,回收過程纔會停止。

不常用的設置

在ThreadPoolExecutor線程池中,有一些不常用的甚至不需要的設置

allowCoreThreadTimeOut:

線程池回收線程只會發生在當前線程池中線程數量大於corePoolSize參數的時候;當線程池中線程數量小於等於corePoolSize參數的時候,回收過程就會停止。 
allowCoreThreadTimeOut設置項可以要求線程池:將包括“核心線程”在內的,沒有任務分配的任何線程,在等待keepAliveTime時間後全部進行回收:

<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;">ThreadPoolExecutor poolExecutor = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ThreadPoolExecutor(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, TimeUnit.MINUTES, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayBlockingQueue<Runnable>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)); poolExecutor.allowCoreThreadTimeOut(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</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></ul>

以下是設置前的效果: 
[圖片] 
以下是設置後的效果: 
[圖片]

prestartAllCoreThreads

前文我們還討論到,當線程池中的線程還沒有達到你設置的corePoolSize參數值的時候,如果有新的任務到來,線程池將創建新的線程運行這個任務,無論之前已經創建的線程是否處於空閒狀態。這個描述可以用下面的示意圖表示出來: 
[圖片] 
prestartAllCoreThreads設置項,可以在線程池創建,但還沒有接收到任何任務的情況下,先行創建符合corePoolSize參數值的線程數:

ThreadPoolExecutor poolExecutor =new ThreadPoolExecutor(5,10,1, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(1));

poolExecutor.prestartAllCoreThreads();


我們繼續討論ThreadPoolExecutor線程池。上面給出的最簡單的ThreadPoolExecutor線程池的使用方式中,我們只採用了ThreadPoolExecutor最簡單的一個構造函數:

<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)</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></ul>

實際上ThreadPoolExecutor線程池有很多種構造函數,其中最複雜的一種構造函數是:

<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>

在上文中我們還沒有介紹的workQueue、threadFactory和handler參數,將是本文講解的重點。

一:ThreadFactory的使用

線程池最主要的一項工作,就是在滿足某些條件的情況下創建線程。而在ThreadPoolExecutor線程池中,創建線程的工作交給ThreadFactory來完成。要使用線程池,就必須要指定ThreadFactory。 
類似於上文中,如果我們使用的構造函數時並沒有指定使用的ThreadFactory,這個時候ThreadPoolExecutor會使用一個默認的ThreadFactory:DefaultThreadFactory。(這個類在Executors工具類中)

當然,在某些特殊業務場景下,還可以使用一個自定義的ThreadFactory線程工廠,如下代碼片段:

<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-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.concurrent.ThreadFactory; <span class="hljs-javadoc" 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;">public</span> <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);">TestThreadFactory</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ThreadFactory</span> {</span> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Thread <span class="hljs-title" style="box-sizing: border-box;">newThread</span>(Runnable r) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Thread(r); } }</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>

二:線程池的等待隊列

在使用ThreadPoolExecutor線程池的時候,需要指定一個實現了BlockingQueue接口的任務等待隊列。在ThreadPoolExecutor線程池的API文檔中,一共推薦了三種等待隊列,它們是:SynchronousQueue、LinkedBlockingQueue和ArrayBlockingQueue;

隊列和棧

● 隊列:是一種特殊的線性結構,允許在線性結構的前端進行刪除/讀取操作;允許在線性結構的後端進行插入操作;這種線性結構具有“先進先出”的操作特點: 
[圖片] 
但是在實際應用中,隊列中的元素有可能不是以“進入的順序”爲排序依據的。例如我們將要講到的PriorityBlockingQueue隊列。 
● 棧:棧也是一種線性結構,但是棧和隊列相比只允許在線性結構的一端進行操作,入棧和出棧都是在一端完成。 
[圖片]

2.1有限隊列

● SynchronousQueue:

“是這樣 一種阻塞隊列,其中每個 put 必須等待一個 take,反之亦然。同步隊列沒有任何內部容量。翻譯一下:這是一個內部沒有任何容量的阻塞隊列,任何一次插入操作的元素都要等待相對的刪除/讀取操作,否則進行插入操作的線程就要一直等待,反之亦然。

<code class="hljs javascript 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;">SynchronousQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>> queue = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> SynchronousQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>>(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 不要使用add,因爲這個隊列內部沒有任何容量,所以會拋出異常“IllegalStateException”</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// queue.add(new Object());</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 操作線程會在這裏被阻塞,直到有其他操作線程取走這個對象</span> queue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</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></ul>

● ArrayBlockingQueue:

一個由數組支持的有界阻塞隊列。此隊列按 FIFO(先進先出)原則對元素進行排序。新元素插入到隊列的尾部,隊列獲取操作則是從隊列頭部開始獲得元素。這是一個典型的“有界緩存區”,固定大小的數組在其中保持生產者插入的元素和使用者提取的元素。一旦創建了這樣的緩存區,就不能再增加其容量。試圖向已滿隊列中放入元素會導致操作受阻塞;試圖從空隊列中提取元素將導致類似阻塞。

<code class="hljs javascript 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-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 我們創建了一個ArrayBlockingQueue,並且設置隊列空間爲2</span> ArrayBlockingQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>> arrayQueue = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayBlockingQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 插入第一個對象</span> arrayQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 插入第二個對象</span> arrayQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 插入第三個對象時,這個操作線程就會被阻塞。</span> arrayQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 請不要使用add操作,和SynchronousQueue的add操作一樣,它們都使用了AbstractQueue中的add實現</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></ul>

2.2無限隊列

● LinkedBlockingQueue:

LinkedBlockingQueue是我們在ThreadPoolExecutor線程池中常用的等待隊列。它可以指定容量也可以不指定容量。由於它具有“無限容量”的特性,所以我還是將它歸入了無限隊列的範疇(實際上任何無限容量的隊列/棧都是有容量的,這個容量就是Integer.MAX_VALUE)。 
LinkedBlockingQueue的實現是基於鏈表結構,而不是類似ArrayBlockingQueue那樣的數組。但實際使用過程中,不需要關心它的內部實現,如果指定了LinkedBlockingQueue的容量大小,那麼它反映出來的使用特性就和ArrayBlockingQueue類似了。

<code class="hljs javascript 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;">LinkedBlockingQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>> linkedQueue = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> LinkedBlockingQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); linkedQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 插入第二個對象</span> linkedQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 插入第三個對象時,這個操作線程就會被阻塞。</span> linkedQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</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></ul>

=======================================

<code class="hljs javascript 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-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 或者如下使用:</span> LinkedBlockingQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>> linkedQueue = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> LinkedBlockingQueue<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>>(); linkedQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 插入第二個對象</span> linkedQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 插入第N個對象時,都不會阻塞</span> linkedQueue.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</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></ul>

● LinkedBlockingDeque

LinkedBlockingDeque是一個基於鏈表的雙端隊列。LinkedBlockingQueue的內部結構決定了它只能從隊列尾部插入,從隊列頭部取出元素;但是LinkedBlockingDeque既可以從尾部插入/取出元素,還可以從頭部插入元素/取出元素。

<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;">LinkedBlockingDeque<TempObject> linkedDeque = new LinkedBlockingDeque<TempObject>()<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;">push</span> ,可以從隊列的頭部插入元素 linkedDeque<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.push</span>(new TempObject(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> linkedDeque<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.push</span>(new TempObject(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> linkedDeque<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.push</span>(new TempObject(<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;">;</span> // poll , 可以從隊列的頭部取出元素 TempObject tempObject = linkedDeque<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.poll</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> // 這裏會打印 tempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.index</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</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;">"tempObject.index = "</span> + tempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getIndex</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> // put , 可以從隊列的尾部插入元素 linkedDeque<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.put</span>(new TempObject(<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;">;</span> linkedDeque<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.put</span>(new TempObject(<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> // pollLast , 可以從隊列尾部取出元素 tempObject = linkedDeque<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.pollLast</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> // 這裏會打印 tempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.index</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</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;">"tempObject.index = "</span> + tempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getIndex</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></ul>

● PriorityBlockingQueue

PriorityBlockingQueue是一個按照優先級進行內部元素排序的無限隊列。存放在PriorityBlockingQueue中的元素必須實現Comparable接口,這樣才能通過實現compareTo()方法進行排序。優先級最高的元素將始終排在隊列的頭部;PriorityBlockingQueue不會保證優先級一樣的元素的排序,也不保證當前隊列中除了優先級最高的元素以外的元素,隨時處於正確排序的位置。 
這是什麼意思呢?PriorityBlockingQueue並不保證除了隊列頭部以外的元素排序一定是正確的。請看下面的示例代碼:

<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;">PriorityBlockingQueue<TempObject> priorityQueue = new PriorityBlockingQueue<TempObject>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.put</span>(new TempObject(-<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> priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.put</span>(new TempObject(<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> priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.put</span>(new TempObject(-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.put</span>(new TempObject(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</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;">5</span> // 實際上在還沒有執行priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.poll</span>()語句的時候,隊列中的第二個元素不一定是<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> TempObject targetTempObject = priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.poll</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;">"tempObject.index = "</span> + targetTempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getIndex</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;">1</span> targetTempObject = priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.poll</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;">"tempObject.index = "</span> + targetTempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getIndex</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;">1</span> targetTempObject = priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.poll</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;">"tempObject.index = "</span> + targetTempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getIndex</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;">5</span> targetTempObject = priorityQueue<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.poll</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;">"tempObject.index = "</span> + targetTempObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getIndex</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></ul>
<code class="hljs axapta 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-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 這個元素類,必須實現Comparable接口</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <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);">TempObject</span> <span class="hljs-inheritance" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span></span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Comparable</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">TempObject</span>> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">index</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> TempObject(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">index</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">index</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">index</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * @return the index */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> getIndex() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">index</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* (non-Javadoc) * @see java.lang.Comparable#compareTo(java.lang.Object) */</span> @Override <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> compareTo(TempObject o) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> o.getIndex() - <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">index</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></ul>

● LinkedTransferQueue

LinkedTransferQueue也是一個無限隊列,它除了具有一般隊列的操作特性外(先進先出),還具有一個阻塞特性:LinkedTransferQueue可以由一對生產者/消費者線程進行操作,當消費者將一個新的元素插入隊列後,消費者線程將會一直等待,直到某一個消費者線程將這個元素取走,反之亦然。 
LinkedTransferQueue的操作特性可以由下面這段代碼提現。在下面的代碼片段中,有兩中類型的線程:生產者和消費者,這兩類線程互相等待對方的操作:

<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;">/** * 生產者線程 */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <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);">ProducerRunnable</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Runnable</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> LinkedTransferQueue<TempObject> linkedQueue; <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;">ProducerRunnable</span>(LinkedTransferQueue<TempObject> linkedQueue) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.linkedQueue = linkedQueue; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</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;">run</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> index = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> ; ; index++) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 向LinkedTransferQueue隊列插入一個新的元素</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;">this</span>.linkedQueue.transfer(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TempObject(index)); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InterruptedException e) { e.printStackTrace(System.out); } } } } <span class="hljs-javadoc" 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;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <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);">ConsumerRunnable</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Runnable</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> LinkedTransferQueue<TempObject> linkedQueue; <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;">ConsumerRunnable</span>(LinkedTransferQueue<TempObject> linkedQueue) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.linkedQueue = linkedQueue; } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</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;">run</span>() { Thread currentThread = Thread.currentThread(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>(!currentThread.isInterrupted()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 等待,直到從LinkedTransferQueue隊列中得到一個元素</span> TempObject targetObject = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.linkedQueue.take(); System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"線程("</span> + currentThread.getId() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">")取得targetObject.index = "</span> + targetObject.getIndex()); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InterruptedException e) { e.printStackTrace(System.out); } } } }</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></ul>

=====以下是啓動代碼:

<code class="hljs lasso 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;">LinkedTransferQueue<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span>TempObject<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> linkedQueue <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> LinkedTransferQueue<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span>TempObject<span class="hljs-subst" style="color: rgb(0, 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-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span> producerThread <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> ProducerRunnable(linkedQueue)); <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;">Thread</span> consumerRunnable1 <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> ConsumerRunnable(linkedQueue)); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span> consumerRunnable2 <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> ConsumerRunnable(linkedQueue)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 開始運行</span> producerThread<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>start(); consumerRunnable1<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>start(); consumerRunnable2<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>start(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 這裏只是爲了main不退出,沒有任何演示含義</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span> currentThread <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Thread</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>currentThread(); synchronized (currentThread) { currentThread<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>wait(); }</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></ul>

三:拒絕任務(handler)

在ThreadPoolExecutor線程池中還有一個重要的接口:RejectedExecutionHandler。當提交給線程池的某一個新任務無法直接被線程池中“核心線程”直接處理,又無法加入等待隊列,也無法創建新的線程執行;又或者線程池已經調用shutdown()方法停止了工作;又或者線程池不是處於正常的工作狀態;這時候ThreadPoolExecutor線程池會拒絕處理這個任務,觸發創建ThreadPoolExecutor線程池時定義的RejectedExecutionHandler接口的實現

在創建ThreadPoolExecutor線程池時,一定會指定RejectedExecutionHandler接口的實現。如果調用的是不需要指定RejectedExecutionHandler接口的構造函數,如:

<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) <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)</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>

那麼ThreadPoolExecutor線程池在創建時,會使用一個默認的RejectedExecutionHandler接口實現,源代碼片段如下:

<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-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <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);">ThreadPoolExecutor</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);">AbstractExecutorService</span> {</span> ...... <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * The default rejected execution handler */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> RejectedExecutionHandler defaultHandler = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AbortPolicy(); ...... <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 可以看到,ThreadPoolExecutor中的兩個沒有指定RejectedExecutionHandler</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 接口的構造函數,都是使用了一個RejectedExecutionHandler接口的默認實現:AbortPolicy</span> <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) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } ...... <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) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); } ...... }</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></ul>

實際上,在ThreadPoolExecutor中已經提供了四種可以直接使用的RejectedExecutionHandler接口的實現:

● CallerRunsPolicy: 
這個拒絕處理器,將直接運行這個任務的run方法。但是,請注意並不是在ThreadPoolExecutor線程池中的線程中運行,而是直接調用這個任務實現的run方法。源代碼如下:

<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-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <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);">CallerRunsPolicy</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">RejectedExecutionHandler</span> {</span> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Creates a {@code CallerRunsPolicy}. */</span> <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;">CallerRunsPolicy</span>() { } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Executes task r in the caller's thread, unless the executor * has been shut down, in which case the task is discarded. * *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> r the runnable task requested to be executed *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> e the executor attempting to execute this task */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</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;">rejectedExecution</span>(Runnable r, ThreadPoolExecutor e) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!e.isShutdown()) { r.run(); } } }</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></ul>

● AbortPolicy:

這個處理器,在任務被拒絕後會創建一個RejectedExecutionException異常並拋出。這個處理過程也是ThreadPoolExecutor線程池默認的RejectedExecutionHandler實現。

● DiscardPolicy: 
DiscardPolicy處理器,將會默默丟棄這個被拒絕的任務,不會拋出異常,也不會通過其他方式執行這個任務的任何一個方法,更不會出現任何的日誌提示。

● DiscardOldestPolicy: 
這個處理器很有意思。它會檢查當前ThreadPoolExecutor線程池的等待隊列。並調用隊列的poll()方法,將當前處於等待隊列列頭的等待任務強行取出,然後再試圖將當前被拒絕的任務提交到線程池執行:

<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-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <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);">DiscardOldestPolicy</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">RejectedExecutionHandler</span> {</span> ...... <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</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;">rejectedExecution</span>(Runnable r, ThreadPoolExecutor e) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } ...... }</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></ul>

實際上查閱這四種ThreadPoolExecutor線程池自帶的拒絕處理器實現,您可以發現CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy處理器針對被拒絕的任務並不是一個很好的處理方式。 
CallerRunsPolicy在非線程池以外直接調用任務的run方法,可能會造成線程安全上的問題;DiscardPolicy默默的忽略掉被拒絕任務,也沒有輸出日誌或者提示,開發人員不會知道線程池的處理過程出現了錯誤;DiscardOldestPolicy中e.getQueue().poll()的方式好像是科學的,但是如果等待隊列出現了容量問題,大多數情況下就是這個線程池的代碼出現了BUG。最科學的的還是AbortPolicy提供的處理方式:拋出異常,由開發人員進行處理。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章