線程池--方便的創(chuàng)建和使用:Executors工具類

Executors為Executor,ExecutorService,ScheduledExecutorService,ThreadFactory和Callable類提供了一些工具方法,類似于集合中的Collections類的功能。


生成線程池采用了工具類Executors的靜態(tài)方法,以下是幾種常見(jiàn)的線程池。
  1>newCachedThreadPool :該線程池比較適合沒(méi)有固定大小并且比較快速就能完成的小任務(wù),它將為每個(gè)任務(wù)創(chuàng)建一個(gè)線程。那這樣子它與直接創(chuàng)建線程對(duì)象(new Thread())有什么區(qū)別呢?看到它的第三個(gè)參數(shù)60L和第四個(gè)參數(shù)TimeUnit.SECONDS了嗎?好處就在于60秒內(nèi)能夠重用已創(chuàng)建的線程。
CachedThreadPool:無(wú)界線程池,可以進(jìn)行自動(dòng)線程回收。
下面是Executors中的newCachedThreadPool()的源代碼:

public static ExecutorService newCachedThreadPool() {  
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());  
    }  

如果線程池的大小超過(guò)了處理任務(wù)所需要的線程,那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來(lái)處理任務(wù)。此線程池不會(huì)對(duì)線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說(shuō)JVM)能夠創(chuàng)建的最大線程大小。SynchronousQueue是一個(gè)是緩沖區(qū)為1的阻塞隊(duì)列。
示例代碼如下:

packagetest;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
 public class ThreadPoolExecutorTest{
        public static void main(String[]args){
            ExecutorService cachedThreadPool= Executors.newCachedThreadPool();
            for(int i=0;i<10;i++){
                final int index=i;
                try{
                    Thread.sleep(index*1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                cachedThreadPool.execute(new Runnable(){
                    public void run(){
                        System.out.println(index);
                    }
                });
            }
        }
    }
//線程池為無(wú)限大,當(dāng)執(zhí)行第二個(gè)任務(wù)時(shí)第一個(gè)任務(wù)已經(jīng)完成,會(huì)復(fù)用執(zhí)行第一個(gè)任務(wù)的線程,而不用每次新建線程。

2> newFixedThreadPool使用的Thread對(duì)象的數(shù)量是有限的,如果提交的任務(wù)數(shù)量大于限制的最大線程數(shù),那么這些任務(wù)講排隊(duì),然后當(dāng)有一個(gè)線程的任務(wù)結(jié)束之后,將會(huì)根據(jù)調(diào)度策略繼續(xù)等待執(zhí)行下一個(gè)任務(wù)。
FixedThreadPool:只有核心線程的線程池,大小固定 (其緩沖隊(duì)列是無(wú)界的) 。
下面是Executors中的newFixedThreadPool()的源代碼:

public static ExecutorService newFixedThreadPool(int nThreads) {  
      return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());  
  }  

創(chuàng)建固定大小的線程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。
示例代碼如下:

package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
  for (int i = 0; i < 10; i++) {
   final int index = i;
   fixedThreadPool.execute(new Runnable() {
    public void run() {
     try {
      System.out.println(index);
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   });
  }
 }
}
//因?yàn)榫€程池大小為3,每個(gè)任務(wù)輸出index后sleep 2秒,所以每?jī)擅氪蛴?個(gè)數(shù)字。
//定長(zhǎng)線程池的大小最好根據(jù)[系統(tǒng)](http://www.2cto.com/os/)資源進(jìn)行設(shè)置。如Runtime.getRuntime().availableProcessors()

3>newSingleThreadExecutor就是線程數(shù)量為1的FixedThreadPool,如果提交了多個(gè)任務(wù),那么這些任務(wù)將會(huì)排隊(duì),每個(gè)任務(wù)都會(huì)在下一個(gè)任務(wù)開始之前運(yùn)行結(jié)束,所有的任務(wù)將會(huì)使用相同的線程。
SingleThreadExecutor:?jiǎn)蝹€(gè)后臺(tái)線程 (其緩沖隊(duì)列是無(wú)界的)
下面是Executors中的newSingleThreadExecutor()的源代碼:

public static ExecutorService newSingleThreadExecutor() {  
        return new FinalizableDelegatedExecutorService  
            (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));  
    }  

創(chuàng)建一個(gè)單線程的線程池。這個(gè)線程池只有一個(gè)核心線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來(lái)替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
示例代碼如下:

package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
  for (int i = 0; i < 10; i++) {
   final int index = i;
   singleThreadExecutor.execute(new Runnable() {
    public void run() {
     try {
      System.out.println(index);
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   });
  }
 }
}
//結(jié)果依次輸出,相當(dāng)于順序執(zhí)行各個(gè)任務(wù)。

4>newScheduledThreadPool創(chuàng)建一個(gè)固定長(zhǎng)度的線程池,而且以延遲或定時(shí)的方式來(lái)執(zhí)行任務(wù)。
ScheduledThreadPool:核心線程池固定,大小無(wú)限的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。

public static ExecutorService newScheduledThreadPool(int corePoolSize) {         
    return new ScheduledThreadPool(corePoolSize, 
              Integer.MAX_VALUE,                                                  
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,                                                    
              new DelayedWorkQueue());    
}

創(chuàng)建一個(gè)周期性執(zhí)行任務(wù)的線程池。如果閑置,非核心線程池會(huì)在DEFAULT_KEEPALIVEMILLIS時(shí)間內(nèi)回收。
示例代碼如下:

package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
  scheduledThreadPool.schedule(new Runnable() {
   public void run() {
    System.out.println("delay 3 seconds");
   }
  }, 3, TimeUnit.SECONDS);
 }
}
//表示延遲3秒執(zhí)行。

定期執(zhí)行示例代碼如下:

package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
  scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
   public void run() {
    System.out.println("delay 1 seconds, and excute every 3 seconds");
   }
  }, 1, 3, TimeUnit.SECONDS);
 }
}
//表示延遲1秒后每3秒執(zhí)行一次。

通過(guò)如上配置的線程池的創(chuàng)建方法源代碼,我們可以發(fā)現(xiàn):
  1、 除了CachedThreadPool使用的是直接提交策略的緩沖隊(duì)列以外,其余兩個(gè)用的采用的都是無(wú)界緩沖隊(duì)列,也就說(shuō),F(xiàn)ixedThreadPool和SingleThreadExecutor創(chuàng)建的線程數(shù)量就不會(huì)超過(guò) corePoolSize。
   2、我們可以再來(lái)看看三個(gè)線程池采用的ThreadPoolExecutor構(gòu)造方法都是同一個(gè),使用的都是默認(rèn)的ThreadFactory和handler:

 private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();  
   
 public ThreadPoolExecutor(int corePoolSize,  
                     int maximumPoolSize,  
                     long keepAliveTime,  
                     TimeUnit unit,  
                     BlockingQueue<Runnable> workQueue) {  
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,  
        Executors.defaultThreadFactory(), defaultHandler);  
}  

也就說(shuō)三個(gè)線程池創(chuàng)建的線程對(duì)象都是同組,優(yōu)先權(quán)等級(jí)為正常的Thread.NORM_PRIORITY(5)的非守護(hù)線程,使用的被拒絕任務(wù)處理方式是直接拋出異常的AbortPolicy策略。

線程池最常用的提交任務(wù)的方法有兩種:
execute:

ExecutorService.execute(Runnable runable);

submit:

FutureTask task = ExecutorService.submit(Runnable runnable);

FutureTask<T> task = ExecutorService.submit(Runnable runnable,T Result);

FutureTask<T> task = ExecutorService.submit(Callable<T> callable);

submit(Callable callable)的實(shí)現(xiàn),submit(Runnable runnable)同理。

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    FutureTask<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

可以看出submit開啟的是有返回結(jié)果的任務(wù),會(huì)返回一個(gè)FutureTask對(duì)象,這樣就能通過(guò)get()方法得到結(jié)果。submit最終調(diào)用的也是execute(Runnable runable),submit只是將Callable對(duì)象或Runnable封裝成一個(gè)FutureTask對(duì)象,因?yàn)镕utureTask是個(gè)Runnable,所以可以在execute中執(zhí)行。關(guān)于Callable對(duì)象和Runnable怎么封裝成FutureTask對(duì)象,見(jiàn)Callable和Future、FutureTask的使用

參考來(lái)自http://blog.csdn.net/zhoufenqin/article/details/51012666
參考來(lái)自http://blog.csdn.net/he90227/article/details/52576452
參考來(lái)自http://www.2cto.com/kf/201606/517766.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,402評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,934評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,168評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,596評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,027評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,398評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,743評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容

  • 一.線程與進(jìn)程相關(guān) 1.進(jìn)程 ??定義:進(jìn)程是具有獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是操作系統(tǒng)分...
    Geeks_Liu閱讀 1,732評(píng)論 2 4
  • 先看幾個(gè)概念:線程:進(jìn)程中負(fù)責(zé)程序執(zhí)行的執(zhí)行單元。一個(gè)進(jìn)程中至少有一個(gè)線程。多線程:解決多任務(wù)同時(shí)執(zhí)行的需求,合理...
    yeying12321閱讀 556評(píng)論 0 0
  • 并發(fā)的學(xué)習(xí)與使用系列 第五篇 線程池的技術(shù)背景 在面向?qū)ο缶幊讨校瑒?chuàng)建和銷毀對(duì)象是很費(fèi)時(shí)間的,因?yàn)閯?chuàng)建一個(gè)對(duì)象要獲...
    SilenceDut閱讀 1,072評(píng)論 1 24
  • 為什么要用線程池 關(guān)于為什么要使用多線程,請(qǐng)參考【多線程與并發(fā)】:線程的創(chuàng)建、狀態(tài)、方法中的最后一點(diǎn)。 那為什么要...
    maxwellyue閱讀 560評(píng)論 0 1
  • 最近項(xiàng)目組組織學(xué)習(xí)線程池,也受到了打擊,以后堅(jiān)持做筆記不偷懶了。 要了解線程池先了解幾個(gè)相關(guān)的概念 線程:進(jìn)程中負(fù)...
    冰鑫925閱讀 270評(píng)論 0 0