Java線程池全面解析

開篇:為什么要使用線程池?

在回答這個(gè)問題之前我們先想想為什么要使用多線程?
answer:由于計(jì)算機(jī)處理器的處理速度極大的超過了計(jì)算機(jī)存儲(chǔ)和通信子系統(tǒng)的處理速度憔购,在單線程情況下當(dāng)進(jìn)行磁盤IO操作或者進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí)會(huì)導(dǎo)致處理器大部分時(shí)間處于空閑狀態(tài)薯蝎,這就造成了處理器資源的浪費(fèi)。同時(shí)Android中規(guī)定主線程只能進(jìn)行UI操作忱叭,對(duì)于耗時(shí)操作則需要放到子線程,否則可能會(huì)導(dǎo)致ANR今艺。所以為了盡量的“壓榨”處理器的效率韵丑,使得計(jì)算機(jī)同時(shí)能夠處理多個(gè)任務(wù),提高任務(wù)執(zhí)行效率虚缎,Java引入了多線程撵彻。

那為什么要使用線程池呢?
answer:對(duì)于每個(gè)jvm都有限定的內(nèi)存大小实牡,若無限制的去創(chuàng)建新線程輕者導(dǎo)致虛擬機(jī)頻繁的GC造成卡頓陌僵,重者直接oom導(dǎo)致虛擬機(jī)崩潰。并且計(jì)算機(jī)處理器的并發(fā)處理數(shù)量也是有限的创坞,超過一定數(shù)量的線程并不會(huì)加快處理器處理的效率碗短。所以為了維護(hù)Java虛擬機(jī)環(huán)境的綠色穩(wěn)定,充分利用處理器的速度题涨,統(tǒng)一管理線程偎谁,對(duì)線程按照一定規(guī)則進(jìn)行調(diào)度處理,Java引入了線程池纲堵。

so:如何去創(chuàng)建線程池巡雨?

我們可以直接使用ThreadPoolExecutor對(duì)象來創(chuàng)建線程池對(duì)象,也可以通過Java提供的四種線程類來快速的創(chuàng)建線程池對(duì)象席函。

代碼:通過ThreadPoolExecutor創(chuàng)建線程池

ExecutorService service = new ThreadPoolExecutor(3,3,
                10, TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());

/**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters and default thread factory.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

corePoolSize:核心線程數(shù)铐望,默認(rèn)一直存在于線程池中,除非allowCoreThreadTimeOut設(shè)置為true茂附,則核心線程也會(huì)在空閑keepAliveTime之后回收蝌以。
maximumPoolSize:最大線程數(shù),包含核心線程和非核心線程何之,非核心線程在空閑keepAliveTime之后會(huì)回收跟畅。
keepAliveTime:空閑線程存活時(shí)間。
unit:時(shí)間單位(時(shí)分秒啥的)溶推。
workQueue:工作隊(duì)列徊件,所有需要執(zhí)行的Runnable對(duì)象都會(huì)被加入到此隊(duì)列中奸攻。
threadFactory: 創(chuàng)建線程的工廠類,默認(rèn)DefaultThreadFactory虱痕。
handler:RejectedExecutionHandler接口對(duì)象睹耐,默認(rèn)AbortPolicy,當(dāng)隊(duì)列達(dá)到限額時(shí)會(huì)阻塞然后執(zhí)行RejectedExecutionHandler中的rejectedExecution方法部翘。

代碼:通過Executors的靜態(tài)方法創(chuàng)建線程池對(duì)象硝训。
通過上述對(duì)ThreadPoolExecutor構(gòu)造器的分析,我們就能很好的理解下面四種線程池的特點(diǎn)新思。
1窖梁、FixedThreadPool,只有核心線程的線程池夹囚,空閑狀態(tài)下默認(rèn)不回收纵刘。代碼如下圖。

ExecutorService service = Executors.newFixedThreadPool(3);

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

2荸哟、CachedThreadPool,只有非核心線程的線程池假哎,線程空閑超過60秒將會(huì)被回收。代碼如下圖鞍历。

ExecutorService service = Executors.newCachedThreadPool();

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

3舵抹、ScheduledThreadPool,既有核心線程(由corePoolSize指定)又有非核心線程的線程池劣砍,非核心線程數(shù)的最大值為Integer.MAX_VALUE惧蛹。代碼如下圖。

ExecutorService service = Executors.newScheduledThreadPool(3);

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
 }

4秆剪、SingleThreadExecutor,只有一個(gè)核心線程的線程池爵政。代碼如下仅讽。

ExecutorService service = Executors.newSingleThreadExecutor();

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

最后:使用線程池對(duì)象去執(zhí)行線程方法。

通過ExecutorService提供的execute钾挟、submit方法洁灵,將線程添加到線程池中進(jìn)行執(zhí)行處理。

代碼:通過execute(Runnable runnable)往線程池添加Runnable對(duì)象

service.execute(new Runnable() {
      @Override
      public void run() {
             System.out.println("我在子線程執(zhí)行掺出,呵呵");
      }
);

代碼:通過submit(Callable<T> callable)往線程池添加Callable對(duì)象

Future<Integer> task = service.submit(new Callable<Integer>() {
      @Override
      public Integer call() throws Exception {
          System.out.println("我也在子線程執(zhí)行徽千,呵呵");
          return 66;
      }
});
//將阻塞當(dāng)前線程直到task獲取到返回值66
task.get();

代碼:通過submit(Runnable runnable)往線程池添加Runnable對(duì)象

Future task1 = service.submit(new Runnable() {
      @Override
      public void run() {
          System.out.println("我也在子線程執(zhí)行,呵呵");
      }
});
        
//將阻塞當(dāng)前線程直到task獲取到返回值null
ask1.get();

代碼:通過submit(Runnable runnable, T result)往線程池添加Runnable對(duì)象并指定返回值result

Future<String> task2 = service.submit(new Runnable() {
    @Override
    public void run() {
        System.out.println("我也在子線程執(zhí)行汤锨,呵呵");
    }
  }, "hello");

 //將阻塞當(dāng)前線程直到task獲取到返回值hello
 task2.get();

這樣我們就可以創(chuàng)建和使用線程池了双抽,寫得不好也點(diǎn)個(gè)贊吧,呵呵闲礼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末牍汹,一起剝皮案震驚了整個(gè)濱河市铐维,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌慎菲,老刑警劉巖嫁蛇,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異露该,居然都是意外死亡睬棚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門解幼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抑党,“玉大人,你說我怎么就攤上這事书幕⌒禄纾” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵台汇,是天一觀的道長(zhǎng)苛骨。 經(jīng)常有香客問我,道長(zhǎng)苟呐,這世上最難降的妖魔是什么痒芝? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮牵素,結(jié)果婚禮上严衬,老公的妹妹穿的比我還像新娘。我一直安慰自己笆呆,他們只是感情好请琳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赠幕,像睡著了一般俄精。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榕堰,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天竖慧,我揣著相機(jī)與錄音,去河邊找鬼逆屡。 笑死圾旨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的魏蔗。 我是一名探鬼主播砍的,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼莺治!你這毒婦竟也來了挨约?” 一聲冷哼從身側(cè)響起味混,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诫惭,沒想到半個(gè)月后翁锡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夕土,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年馆衔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怨绣。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡角溃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篮撑,到底是詐尸還是另有隱情减细,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布赢笨,位于F島的核電站未蝌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏茧妒。R本人自食惡果不足惜萧吠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桐筏。 院中可真熱鬧纸型,春花似錦、人聲如沸梅忌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牧氮。三九已至琼腔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹋笼,已是汗流浹背展姐。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工躁垛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留剖毯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓教馆,卻偏偏與公主長(zhǎng)得像逊谋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子土铺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359