任務的執行與線程池(上)

<div class="htmledit_views" id="content_views"> <p>原文出處:</p>html

<p>https://mp.weixin.qq.com/s/p3JZERyZXnF8jR_3KKIGJA</p>java

<p>寫做本文時參考了《java併發編程實戰》、《java併發編程的藝術》、java源碼以及一些博客文章,力求把這個專題的知識講的足夠全面,最重要的是通俗易懂,如文中有錯誤請與我聯繫。爲保證你把這些知識徹底掌握,最好使用電腦觀看,投機取巧是學不到東西的,對本身誠實一點哈。</p>程序員

<h3><a name="t0"></a><a name="t0"></a>任務執行的幾種方式</h3>編程

<p>咱們先來看一個現實生活中的例子,拿銀行來講,天天都會有不少的客戶來辦理業務,每一個人辦理一次業務均可以稱爲一個<code>任務</code>,爲了圓滿的完成這些任務,銀行能夠按照下邊的這幾種方式來安排工做。</p>緩存

<p>串行執行</p>併發

<p>銀行可讓等待辦理業務的客戶排成一道長龍,只留一個業務員來辦理業務,對應到java程序裏,就至關於用1個線程來依次處理全部的任務,這種執行方式咱們稱之爲<code>串行執行</code>。</p>框架

<p><code>串行執行</code>的劣勢很是好理解,假若有一個辦理業務的客戶十分墨跡,將影響到後邊全部排隊的客戶,對應到線程裏,若是有一個任務裏調用了某些阻塞操做,好比<code>I/O</code>操做,那後邊的任務將須要等待很長時間,用java代碼表示出來就像這個樣子:</p>ide

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">process</span><span class="hljs-params">(List&lt;Runnable&gt;&nbsp;runnables)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">for</span>&nbsp;(Runnable&nbsp;r&nbsp;:&nbsp;runnables)&nbsp;{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.run();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>工具

<p>爲每一個任務建立一個線程</p>學習

<p>考慮到用一個業務員來處理業務太慢了,每天遭客戶投訴,新來的行長拍大腿決定每一個客戶都要有一個業務員單獨服務,用java語言表述就是爲每一個任務來建立一個線程單獨處理。這樣一開始辦理業務的客戶很少的時候這一招的確聽有效,客戶們不用再排隊了,也不用由於前邊的某個客戶十分墨跡而影響到後邊客戶的處理效率了,因此銀行一天能接待的客戶也明顯增多了。用java語言描述,就是程序的<code>響應性</code>和<code>吞吐量</code>明顯提升了,接下來用java代碼表示一下這個過程:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">process</span><span class="hljs-params">(List&lt;Runnable&gt;&nbsp;runnables)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">for</span>&nbsp;(Runnable&nbsp;r&nbsp;:&nbsp;runnables)&nbsp;{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">new</span>&nbsp;Thread(r).start();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>可是隨着辦理業務的人愈來愈多,這種模式的弊端慢慢的暴露出來了,好比須要不少的業務員,每一個業務員上崗前都要培訓就浪費了不少時間,而後銀行的櫃檯漸漸不夠用了,慢慢的辦理業務的人連大廳都放不下了,人越多越混亂了,致使最後的效率其實不升反降了。對於java的線程來講也存在這種問題,咱們前邊說過,線程的建立和銷燬都是須要系統資源的,並且線程的上下文切換也要浪費不少時間,線程越多浪費的時間越多;在相同時間內分配在每一個線程頭上的處理時間就越少;每一個線程在執行任務的時候都須要分配內存,若是無限制的建立線程,確定會致使內存不夠用的,並且通常的操做系統對線程的建立數量是有限制的。</p>

<p>因此結論就是:在必定範圍內增長線程數量的確能夠提高系統的處理能力,可是過多的建立線程將會下降系統的處理速度,若是無限制的建立線程,將會使系統崩潰。</p>

<p>線程的重複利用</p>

<p>在經歷了一次銀行崩潰以後,行長決定只留下10個業務員,讓辦理業務的客戶都排成一隊,哪一個業務員空閒,就把隊頭的客戶叫走,這樣便可以提高處理效率,又能夠避免業務員太多帶來的煩惱,完美!咱們用java代碼表示一下:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">process</span><span class="hljs-params">(List&lt;Runnable&gt;&nbsp;runnables)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">final</span>&nbsp;Queue&lt;Runnable&gt;&nbsp;queue&nbsp;=&nbsp;<span class="hljs-keyword">new</span>&nbsp;ConcurrentLinkedQueue&lt;&gt;(runnables);&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//同步隊列</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">for</span>&nbsp;(<span class="hljs-keyword">int</span>&nbsp;i&nbsp;=&nbsp;<span class="hljs-number">0</span>;&nbsp;i&nbsp;&lt;&nbsp;<span class="hljs-number">10</span>;&nbsp;i++)&nbsp;{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">new</span>&nbsp;Thread(<span class="hljs-keyword">new</span>&nbsp;Runnable()&nbsp;{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-meta">@Override</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">run</span><span class="hljs-params">()</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">while</span>&nbsp;(<span class="hljs-keyword">true</span>)&nbsp;{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Runnable&nbsp;r&nbsp;=&nbsp;queue.poll();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">if</span>&nbsp;(r&nbsp;==&nbsp;<span class="hljs-keyword">null</span>)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//若是沒任務了就退出</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">break</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.run();&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//執行任務</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}).start();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}&nbsp;&nbsp;&nbsp;&nbsp;</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>能夠看到,咱們一共建立了10個線程,每一個線程都試圖從任務隊列中取任務來作,直到任務隊列裏沒有任務了才退出。</p>

<h3><a name="t1"></a><a name="t1"></a>Executor框架</h3>

<p>咱們上邊嘮叨的3種任務的執行方式用一個高大上的詞兒描述就是任務的<code>執行策略</code>,每一個<code>執行策略</code>都要規定不少任務的執行細節,好比用多少線程去執行任務;是在把線程都建立好以後再去處理任務,仍是遇到任務以後再建立線程;建立好的線程在空閒的時候能不能銷燬等等的問題,若是咱們樂意,咱們能夠定義不少的<code>執行策略</code>。</p>

<p>Executor接口的提出</p>

<p>其實對於客戶端程序員來講,每次在執行某些任務的時候都要設計一種新的執行策略太累人了,因此設計java的大叔們就幫助客戶端程序員設計了這樣的一個接口:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">interface</span>&nbsp;<span class="hljs-title">Executor</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">execute</span><span class="hljs-params">(Runnable&nbsp;command)</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p><code>Executor</code>翻譯過來的意思就是<code>執行器</code>,設計java的大叔們針對不一樣的<code>執行策略</code>定義了不一樣的<code>Executor</code>子類(咱們稍後介紹)。客戶端程序員只須要把<code>Runnable</code>任務放到<code>執行器</code>的<code>execute</code>方法裏就表示任務提交了,具體提交之後這些任務怎麼分配線程怎麼執行就無論了。這也就是:把任務的提交和執行解耦開來了。咱們先舉個例子看一下<code>執行器</code>怎麼用:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">process</span><span class="hljs-params">(List&lt;Runnable&gt;&nbsp;runnables)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;Executor&nbsp;executor&nbsp;=&nbsp;Executors.newFixedThreadPool(<span class="hljs-number">10</span>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//建立包含10個線程的執行器</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">for</span>&nbsp;(Runnable&nbsp;r&nbsp;:&nbsp;runnables)&nbsp;{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executor.execute(r);&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//提交任務</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>其中的<code>Executors</code>類提供了一系列建立<code>Executor</code>子類的靜態方法,上邊<code>newFixedThreadPool(10)</code>方法表明建立了一個包含10個線程<code>Executor</code>,能夠用這10個線程去執行任務。更多的使用方式咱們下節詳細嘮叨。</p>

<p>咱們也能夠自定義本身的<code>執行策略</code>,好比對於<code>串行執行</code>的策略,能夠定義一個這樣的<code>Executor</code>子類:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">SerialExecutor</span>&nbsp;<span class="hljs-keyword">implements</span>&nbsp;<span class="hljs-title">Executor</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-meta">@Override</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">execute</span><span class="hljs-params">(Runnbale&nbsp;r)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.run();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>對於<code>爲每一個任務建立一個線程</code>的策略,能夠定義一個這樣的子類:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">ThreadPerRunnalbeExecutor</span>&nbsp;<span class="hljs-keyword">implements</span>&nbsp;<span class="hljs-title">Executor</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-meta">@Override</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">executor</span><span class="hljs-params">(Runnbale&nbsp;r)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">new</span>&nbsp;Thread(r).start();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>咱們下邊深刻看一下java類庫中都針對哪些<code>執行策略</code>提供了<code>執行器</code>。</p>

<p>類庫中的線程池</p>

<p>因爲<code>Executor</code>子類負責執行任務,因此裏邊確定要包含一些線程,才能使用這些線程去執行任務,因此<code>Executor</code>子類也叫作<code>線程池</code>,寓意盛放線程的池子。通常狀況下,調用&nbsp;Executor&nbsp;的&nbsp;execute方法會把該任務塞到一個隊列中,而後線程池中的線程從這個隊列中取任務執行。</p>

<p><code>Executors</code>類裏提供了建立適用於各類場景<code>線程池</code>的工具方法(靜態方法),咱們看一下經常使用的幾個:</p>

<pre class="has" name="code"><code class="hljs go">注意,是<span class="hljs-string">`Executors`</span>類,不是<span class="hljs-string">`Executor`</span>接口,不要認錯哦。就和<span class="hljs-string">`Collections`</span>和<span class="hljs-string">`Collection`</span>不是一個東西同樣~ </code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p><img alt="" class="has" height="168" src="https://img2018.cnblogs.com/blog/1112483/201907/1112483-20190715215250397-1400413508.png" width="679"></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>你們能夠看到有的方法返回類型是<code>ExecutorService</code>,有的是<code>ScheduledExecutorService</code>,其實這兩個都是<code>Executor</code>的子接口,稍後咱們會詳細說道的。下邊咱們看一下這幾個方法的詳細用法。</p>

<p>newFixedThreadPool(int nThreads)</p>

<p>經過此方法能夠建立一個擁有固定線程數量的線程池,具體的線程數量由<code>nThreads</code>參數指定。</p>

<p>這裏所說的固定線程數量的線程池的意思是:最開始該線程池中的線程數爲0,以後每提交一個任務就會建立一個線程,直到線程數等於指定的<code>nThreads</code>參數,此後線程數量將再也不變化。</p>

<p>newCachedThreadPool()</p>

<p>經過此方法能夠建立一個可緩存的線程池。</p>

<p>可緩存的意思是:會爲每一個任務都分配一個線程,可是若是一個線程執行完任務後長時間(60秒)沒有新的任務可執行,該線程將被回收。</p>

<p>newSingleThreadExecutor()</p>

<p>經過此方法能夠建立單線程的線程池。</p>

<p>其實只有一個線程也很差意思叫線程池了,不過爲了統一名稱,也就勉強叫一聲線程池吧~ 被提交到該線程的任務將在一個線程中<code>串行</code>執行,而且能確保任務能夠按照隊列中的順序串行執行。</p>

<p>newScheduledThreadPool(int corePoolSize)</p>

<p>經過此方法能夠建立固定線程數量的線程池,並且以延遲或定時的方式來執行任務。怎麼以延遲或定時的方式執行任務呢?咱們看一下該方法的返回類型<code>ScheduledExecutorService</code>裏提供的幾個方法:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln" style="width:1060px"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">interface</span>&nbsp;<span class="hljs-title">ScheduledExecutorService</span>&nbsp;<span class="hljs-keyword">extends</span>&nbsp;<span class="hljs-title">ExecutorService</span>&nbsp;</span>{&nbsp;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">public</span>&nbsp;ScheduledFuture&lt;?&gt;&nbsp;schedule(Runnable&nbsp;command,&nbsp;<span class="hljs-keyword">long</span>&nbsp;delay,&nbsp;TimeUnit&nbsp;unit);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">public</span>&nbsp;&lt;V&gt;&nbsp;<span class="hljs-function">ScheduledFuture&lt;V&gt;&nbsp;<span class="hljs-title">schedule</span><span class="hljs-params">(Callable&lt;V&gt;&nbsp;callable,&nbsp;<span class="hljs-keyword">long</span>&nbsp;delay,&nbsp;TimeUnit&nbsp;unit)</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">public</span>&nbsp;ScheduledFuture&lt;?&gt;&nbsp;scheduleAtFixedRate(Runnable&nbsp;command,&nbsp;<span class="hljs-keyword">long</span>&nbsp;initialDelay,&nbsp;<span class="hljs-keyword">long</span>&nbsp;period,&nbsp;TimeUnit&nbsp;unit);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">public</span>&nbsp;ScheduledFuture&lt;?&gt;&nbsp;scheduleWithFixedDelay(Runnable&nbsp;command,&nbsp;<span class="hljs-keyword">long</span>&nbsp;initialDelay,&nbsp;<span class="hljs-keyword">long</span>&nbsp;delay,&nbsp;TimeUnit&nbsp;unit);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>真的很抱歉,這段代碼裏出現了<code>ScheduledFuture</code>和<code>Callable</code>兩個你可能不認識的東東,咱們先不理它們,以後說到的時候再看,返回這個線程池,看看這幾個方法(參數中帶<code>Callable</code>的先略過)都是幹什麼的:</p>

<p><img alt="" class="has" height="262" src="https://img2018.cnblogs.com/blog/1112483/201907/1112483-20190715215327144-366079967.png" width="676"></p>

<p>其中後兩個方法的參數都是如出一轍的,並且意義貌似也有點像,那就舉個現實生活的例子吧,好比有不少同窗在跑道上跑圈。</p>

<p><code>scheduleAtFixedRate</code>規定在前邊的同窗出發1分鐘後第後邊同窗就能夠跑了,若是在1分鐘以內前邊的同窗順利跑完了1圈,後邊的同窗就能夠按照約定出發,不然的話雖然1分鐘時間到了,後邊的同窗仍是要等待前邊的同窗到達終點後才能夠出發。</p>

<p><code>scheduleWithFixedDelay</code>規定在前邊的同窗跑完一圈以後再過1分鐘才能出發。</p>

<p>示例</p>

<p>好了,知道了這些方法是神馬意思,寫個程序瞅瞅:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">import</span>&nbsp;java.util.concurrent.Executors;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">import</span>&nbsp;java.util.concurrent.ScheduledExecutorService;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">import</span>&nbsp;java.util.concurrent.TimeUnit;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">ScheduleDemo</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">private</span>&nbsp;<span class="hljs-keyword">static</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">PrintTask</span>&nbsp;<span class="hljs-keyword">implements</span>&nbsp;<span class="hljs-title">Runnable</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">private</span>&nbsp;String&nbsp;s;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-title">PrintTask</span><span class="hljs-params">(String&nbsp;s)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">this</span>.s&nbsp;=&nbsp;s;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-meta">@Override</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">run</span><span class="hljs-params">()</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(s);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">static</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">main</span><span class="hljs-params">(String[]&nbsp;args)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScheduledExecutorService&nbsp;service&nbsp;=&nbsp;Executors.newScheduledThreadPool(<span class="hljs-number">10</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="23"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="24"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//隔1秒後打印</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="25"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;service.schedule(<span class="hljs-keyword">new</span>&nbsp;PrintTask(<span class="hljs-string">"1"</span>),&nbsp;<span class="hljs-number">1</span>,&nbsp;TimeUnit.SECONDS);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="26"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="27"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//首次5秒後打印,每隔1秒打印一次</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="28"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;service.scheduleAtFixedRate(<span class="hljs-keyword">new</span>&nbsp;PrintTask(<span class="hljs-string">"2"</span>),&nbsp;<span class="hljs-number">5</span>,&nbsp;<span class="hljs-number">1</span>,&nbsp;TimeUnit.SECONDS);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="29"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="30"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>Callable與Future</p>

<p>咱們以前都是以<code>Runnable</code>表示任務的,再次看一下這個接口:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">interface</span>&nbsp;<span class="hljs-title">Runnable</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">run</span><span class="hljs-params">()</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>它裏邊只有一個返回<code>void</code>的<code>run</code>方法,咱們定義一個計算兩個值大小的<code>Runnable</code>:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">AddTask</span>&nbsp;<span class="hljs-keyword">implements</span>&nbsp;<span class="hljs-title">Runnable</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">private</span>&nbsp;<span class="hljs-keyword">int</span>&nbsp;i;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">private</span>&nbsp;<span class="hljs-keyword">int</span>&nbsp;j;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-title">AddTask</span><span class="hljs-params">(<span class="hljs-keyword">int</span>&nbsp;i,&nbsp;<span class="hljs-keyword">int</span>&nbsp;j)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">this</span>.i&nbsp;=&nbsp;i;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">this</span>.j&nbsp;=&nbsp;j;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-meta">@Override</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">run</span><span class="hljs-params">()</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">int</span>&nbsp;sum&nbsp;=&nbsp;i&nbsp;+&nbsp;j;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span class="hljs-string">"線程t的運算結果:"</span>&nbsp;+&nbsp;sum);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>下邊咱們在<code>main</code>線程中建立一個<code>t</code>線程去執行這個任務:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">Test</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">static</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">main</span><span class="hljs-params">(String[]&nbsp;args)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AddTask&nbsp;task&nbsp;=&nbsp;<span class="hljs-keyword">new</span>&nbsp;AddTask(<span class="hljs-number">1</span>,&nbsp;<span class="hljs-number">2</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;t&nbsp;=&nbsp;<span class="hljs-keyword">new</span>&nbsp;Thread(task,&nbsp;<span class="hljs-string">"t"</span>);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.start();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>執行結果是:</p>

<pre class="has" name="code"><code class="hljs">線程t的運算結果:3 </code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>以上是一個很常見的顯式建立線程去運行<code>Runnable</code>任務的使用案例,可是這種方式有個問題,就是<code>main</code>線程一旦調用了<code>t</code>線程的<code>start</code>方法,這兩個線程就好像不要緊了,也就是說main線程既不知道t線程如今是否是運行完了,也不知道t線程執行的任務的結果是什麼,也不知道在運行任務的過程當中是否是發生了異常。因此設計java的大叔們在設計<code>Executor</code>的各類子類的時候特地把這個事情考慮了進去,提出了帶返回值的<code>Callable</code>任務以及用於檢測任務執行狀況的<code>Future</code>接口。</p>

<p><code>Callable</code>是一個接口,它表明一個任務,與<code>Runnable</code>不一樣的是,這個任務是有返回值的:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">interface</span>&nbsp;<span class="hljs-title">Callable</span>&lt;<span class="hljs-title">V</span>&gt;&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function">V&nbsp;<span class="hljs-title">call</span><span class="hljs-params">()</span>&nbsp;<span class="hljs-keyword">throws</span>&nbsp;Exception</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>咱們能夠把<code>AddTask</code>定義成一個<code>Callable</code>任務:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">import</span>&nbsp;java.util.concurrent.Callable;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">AddTask</span>&nbsp;<span class="hljs-keyword">implements</span>&nbsp;<span class="hljs-title">Callable</span>&lt;<span class="hljs-title">Integer</span>&gt;&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">private</span>&nbsp;<span class="hljs-keyword">int</span>&nbsp;i;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">private</span>&nbsp;<span class="hljs-keyword">int</span>&nbsp;j;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-title">AddTask</span><span class="hljs-params">(<span class="hljs-keyword">int</span>&nbsp;i,&nbsp;<span class="hljs-keyword">int</span>&nbsp;j)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">this</span>.i&nbsp;=&nbsp;i;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">this</span>.j&nbsp;=&nbsp;j;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-meta">@Override</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;Integer&nbsp;<span class="hljs-title">call</span><span class="hljs-params">()</span>&nbsp;<span class="hljs-keyword">throws</span>&nbsp;Exception&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">int</span>&nbsp;sum&nbsp;=&nbsp;&nbsp;i&nbsp;+&nbsp;j;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span class="hljs-string">"線程main的運算結果:"</span>&nbsp;+&nbsp;sum);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">return</span>&nbsp;sum;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>其中的<code>call</code>方法返回了兩個字段的和。這種帶返回值的<code>Callable</code>任務不能像<code>Runnable</code>同樣直接經過<code>Thread</code>的構造方法傳入,在<code>Executor</code>的子接口<code>ExecutorService</code>中規定了<code>Callable</code>任務的提交方式:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">interface</span>&nbsp;<span class="hljs-title">ExecutorService</span>&nbsp;<span class="hljs-keyword">extends</span>&nbsp;<span class="hljs-title">Executor</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//&nbsp;任務提交操做</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&lt;T&gt;&nbsp;<span class="hljs-function">Future&lt;T&gt;&nbsp;<span class="hljs-title">submit</span><span class="hljs-params">(Callable&lt;T&gt;&nbsp;task)</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;Future&lt;?&gt;&nbsp;submit(Runnable&nbsp;task);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&lt;T&gt;&nbsp;<span class="hljs-function">Future&lt;T&gt;&nbsp;<span class="hljs-title">submit</span><span class="hljs-params">(Runnable&nbsp;task,&nbsp;T&nbsp;result)</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//&nbsp;生命週期管理</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">shutdown</span><span class="hljs-params">()</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function">List&lt;Runnable&gt;&nbsp;<span class="hljs-title">shutdownNow</span><span class="hljs-params">()</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">boolean</span>&nbsp;<span class="hljs-title">isShutdown</span><span class="hljs-params">()</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">boolean</span>&nbsp;<span class="hljs-title">isTerminated</span><span class="hljs-params">()</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">boolean</span>&nbsp;<span class="hljs-title">awaitTermination</span><span class="hljs-params">(<span class="hljs-keyword">long</span>&nbsp;timeout,&nbsp;TimeUnit&nbsp;unit)</span>&nbsp;<span class="hljs-keyword">throws</span>&nbsp;InterruptedException</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//&nbsp;...&nbsp;省略了各類方便提交任務的方法</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>能夠看到,<code>ExecutorService</code>主要擴展了任務的提交方式、生命週期管理(稍後立刻嘮叨)和一系列方便提交任務的方法(這個沒啥意思,等遇到了再說哈),咱們這一節主要嘮叨任務的提交方式。這個<code>ExecutorService</code>咱們以前見過,<code>Executors</code>的各類建立<code>線程池</code>的工具方法的返回類型就是它,咱們再重溫一遍:</p>

<p><img alt="" class="has" height="173" src="https://img2018.cnblogs.com/blog/1112483/201907/1112483-20190715215356046-1389129749.png" width="680"></p>

<p>&nbsp;</p>

<p>(注:<code>ScheduledExecutorService</code>繼承了<code>ExecutorService</code>)</p>

<p>也就是說,各類線程池其實都是實現了&nbsp;ExecutorService&nbsp;的,Callable&nbsp;任務須要提交到線程池中才能運行:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">Test</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">static</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">main</span><span class="hljs-params">(String[]&nbsp;args)</span>&nbsp;</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;service&nbsp;=&nbsp;Executors.newCachedThreadPool();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;service.submit(<span class="hljs-keyword">new</span>&nbsp;AddTask(<span class="hljs-number">1</span>,&nbsp;<span class="hljs-number">2</span>));</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>執行結果是:</p>

<pre class="has" name="code"><code class="hljs">線程t的運算結果:3 </code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>帶返回值的<code>Callable</code>任務經過<code>線程池</code>的<code>submit</code>方法總算是提交併執行了哈哈。其實無論是<code>Runnable</code>任務仍是<code>Callable</code>任務,線程池執行的任務能夠劃分爲4個生命週期階段:</p>

<ol><li> <p>建立:建立任務對象的時期。</p> </li> <li> <p>提交:調用線程池的<code>excute</code>或者<code>submit</code>方法後,將任務塞到任務隊列的時期。</p> </li> <li> <p>執行中:某個線程從任務隊列中將任務取出開始執行的時期。</p> </li> <li> <p>完成:任務執行結束。</p> </li> </ol><p>任務的生命週期只能前進,不能後退,也就是說若是一個任務已經執行完成了,也就是處於<code>完成</code>階段,那麼就沒法後退到<code>提交</code>階段。咱們能夠在任務的執行過程當中取消任務,如何取消咱們以後會詳細嘮叨。若是咱們經過線程池的<code>submit</code>方法提交了任務,那咱們能夠獲得一個<code>Future</code>對象,它表示一個任務的實時執行狀態,並提供了判斷是否已經完成或取消的方法,也提供了取消任務和獲取任務的運行結果的方法。線程池的<code>submit</code>方法的返回類型<code>Future</code>,實際上是一個接口:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln" style="width:959px"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-class"><span class="hljs-keyword">interface</span>&nbsp;<span class="hljs-title">Future</span>&lt;<span class="hljs-title">V</span>&gt;&nbsp;</span>{&nbsp;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function">V&nbsp;<span class="hljs-title">get</span><span class="hljs-params">()</span>&nbsp;<span class="hljs-keyword">throws</span>&nbsp;InterruptedException,&nbsp;ExecutionException</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function">V&nbsp;<span class="hljs-title">get</span><span class="hljs-params">(<span class="hljs-keyword">long</span>&nbsp;timeout,&nbsp;TimeUnit&nbsp;unit)</span>&nbsp;<span class="hljs-keyword">throws</span>&nbsp;InterruptedException,&nbsp;ExecutionException,&nbsp;TimeoutException</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">boolean</span>&nbsp;<span class="hljs-title">isDone</span><span class="hljs-params">()</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">boolean</span>&nbsp;<span class="hljs-title">cancel</span><span class="hljs-params">(<span class="hljs-keyword">boolean</span>&nbsp;mayInterruptIfRunning)</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">boolean</span>&nbsp;<span class="hljs-title">isCancelled</span><span class="hljs-params">()</span></span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>各個方法的大體描述以下:</p>

<p><img alt="" class="has" height="222" src="https://img-blog.csdnimg.cn/20190530213238661.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpdWNoYW5namllMDExMg==,size_16,color_FFFFFF,t_70" width="681"></p>

<p>須要注意的是,若是該任務已經完成,那麼<code>get</code>方法將會當即返回,若是任務正常完成的話,會返回執行結果,如果拋出異常完成的話,將會將該異常包裝成<code>ExecutionException</code>後從新拋出,若是任務被取消,則調用<code>get</code>方法會拋出<code>CancellationExection</code>異常。下邊咱們試試<code>Future</code>的用法:</p>

<pre class="has" name="code"><code class="hljs cs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">class</span>&nbsp;<span class="hljs-title">Test</span>&nbsp;{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function"><span class="hljs-keyword">public</span>&nbsp;<span class="hljs-keyword">static</span>&nbsp;<span class="hljs-keyword">void</span>&nbsp;<span class="hljs-title">main</span>(<span class="hljs-params">String[]&nbsp;args</span>)&nbsp;throws&nbsp;Exception</span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutorService&nbsp;service&nbsp;=&nbsp;Executors.newCachedThreadPool();&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//建立一個線程池</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Future&lt;Integer&gt;&nbsp;future&nbsp;=&nbsp;service.submit(<span class="hljs-keyword">new</span>&nbsp;AddTask(<span class="hljs-number">1</span>,&nbsp;<span class="hljs-number">2</span>));&nbsp;<span class="hljs-comment">//提交一個任務</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword">int</span>&nbsp;result&nbsp;=&nbsp;future.<span class="hljs-keyword">get</span>();&nbsp;&nbsp;<span class="hljs-comment">//在任務執行完成以前,該方法將一直阻塞</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"線程main的運算結果:"</span>&nbsp;+&nbsp;result);</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&nbsp;&nbsp;&nbsp;&nbsp;}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>執行結果是:</p>

<pre class="has" name="code"><code class="hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">線程t的運算結果:3</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">線程main的運算結果:3</div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>有時候咱們但願在指定時間內等待另外一個線程的執行結果,那就能夠可使用帶時間限制的<code>get</code>方法,另外的幾個方法咱們以後再詳細的說。</p>

<p>視線再返回到<code>ExecutorService</code>接口上來,除了參數類型爲<code>Callable</code>的<code>submit</code>方法,這個接口還提供了兩個重載方法:</p>

<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">Future&lt;?&gt;&nbsp;submit(Runnable&nbsp;task);&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment">//第1個重載方法</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">&lt;T&gt;&nbsp;<span class="hljs-function">Future&lt;T&gt;&nbsp;<span class="hljs-title">submit</span><span class="hljs-params">(Runnable&nbsp;task,&nbsp;T&nbsp;result)</span></span>;&nbsp;&nbsp;<span class="hljs-comment">//第2個重載方法</span></div></div></li></ol></code><div class="hljs-button {2}" data-title="複製" onclick="hljs.copyCode(event)"></div></pre>

<p>對於第1個只有一個<code>Runnable</code>參數的重載方法來講,因爲<code>Runnable</code>的<code>run</code>方法並無返回值,也就是說任務是沒有返回值的,因此在該任務完成以後,對應的<code>Future</code>對象的<code>get</code>方法的返回值就是<code>null</code>。雖然不能得到返回值,可是咱們仍是能夠調用<code>Future</code>的其餘方法,好比<code>isDone</code>表示任務是否已經完成,<code>isCancelled</code>表示任務是否已經被取消,<code>cancel</code>表示嘗試取消一個任務(稍後詳細說明)。</p>

<p>對於第2個帶有兩個參數的重載方法來講,其實和第1個的意思差很少,只不過咱們能夠指定該<code>Runnable</code>任務對應的<code>Future</code>對象的<code>get</code>方法的返回值,也就是說方法參數<code>result</code>其實就是<code>get</code>方法的返回值。有的小夥伴會問了,你還沒執行任務的時候就把任務返回值給指定了是幾個意思???我也不是很清楚,可能有用到的地方吧,你先記住用法就行了。</p>

<p><span style="color:#7c79e5;">小貼士:</span></p>

<p><span style="color:#7c79e5;">若是你已經大體理解了Callable和Future的用法,有沒有想過它們是怎麼實現的呢?其實無非是線程間通訊的那一套東西,一個線程等待另外一個線程完成任務以後的通知,而後經過某個共享變量來傳遞數據,若是你有興趣的話能夠試着本身實現一個Callable和Future。</span></p>

<p>若是你從本文中學到的知識有助於你解決眼前的工做、學習問題,或者對你的升職加薪起到了做用,能夠點擊下方喜歡做者,謝謝~&nbsp;</p> </div>

相關文章
相關標籤/搜索