摘要:創(chuàng)建方法最大線程數(shù)即源碼單線程化的線程池有且僅有一個(gè)工作線程執(zhí)行任務(wù)所有任務(wù)按照指定順序執(zhí)行,即遵循隊(duì)列的入隊(duì)出隊(duì)規(guī)則創(chuàng)建方法源碼還有一個(gè)結(jié)合了和,就不介紹了,基本不用。
*本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布
為什么用線程池
創(chuàng)建/銷毀線程伴隨著系統(tǒng)開(kāi)銷,過(guò)于頻繁的創(chuàng)建/銷毀線程,會(huì)很大程度上影響處理效率
>例如: > >記創(chuàng)建線程消耗時(shí)間T1,執(zhí)行任務(wù)消耗時(shí)間T2,銷毀線程消耗時(shí)間T3 > >如果T1+T3>T2,那么是不是說(shuō)開(kāi)啟一個(gè)線程來(lái)執(zhí)行這個(gè)任務(wù)太不劃算了! > >正好,線程池緩存線程,可用已有的閑置線程來(lái)執(zhí)行新任務(wù),避免了T1+T3帶來(lái)的系統(tǒng)開(kāi)銷
線程并發(fā)數(shù)量過(guò)多,搶占系統(tǒng)資源從而導(dǎo)致阻塞
>我們知道線程能共享系統(tǒng)資源,如果同時(shí)執(zhí)行的線程過(guò)多,就有可能導(dǎo)致系統(tǒng)資源不足而產(chǎn)生阻塞的情況 > >運(yùn)用線程池能有效的控制線程最大并發(fā)數(shù),避免以上的問(wèn)題
對(duì)線程進(jìn)行一些簡(jiǎn)單的管理
> 比如:延時(shí)執(zhí)行、定時(shí)循環(huán)執(zhí)行的策略等 > > 運(yùn)用線程池都能進(jìn)行很好的實(shí)現(xiàn)線程池ThreadPoolExecutor
既然Android中線程池來(lái)自于Java,那么研究Android線程池其實(shí)也可以說(shuō)是研究Java中的線程池
在Java中,線程池的概念是Executor這個(gè)接口,具體實(shí)現(xiàn)為ThreadPoolExecutor類,學(xué)習(xí)Java中的線程池,就可以直接學(xué)習(xí)他了
對(duì)線程池的配置,就是對(duì)ThreadPoolExecutor構(gòu)造函數(shù)的參數(shù)的配置,既然這些參數(shù)這么重要,就來(lái)看看構(gòu)造函數(shù)的各個(gè)參數(shù)吧
ThreadPoolExecutor提供了四個(gè)構(gòu)造函數(shù)//五個(gè)參數(shù)的構(gòu)造函數(shù) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueworkQueue) //六個(gè)參數(shù)的構(gòu)造函數(shù)-1 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) //六個(gè)參數(shù)的構(gòu)造函數(shù)-2 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) //七個(gè)參數(shù)的構(gòu)造函數(shù) public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
我知道你看到這些構(gòu)造函數(shù)和我一樣也是嚇呆了,但其實(shí)一共就7種類型,理解起來(lái)簡(jiǎn)直和理解一周有7天一樣簡(jiǎn)單,而且一周有兩天是周末,其實(shí)也就只有5天需要了解!相信我,畢竟扯皮,我比較擅長(zhǎng)
int corePoolSize => 該線程池中核心線程數(shù)最大值
> **核心線程:** > > 線程池新建線程的時(shí)候,如果當(dāng)前線程總數(shù)小于corePoolSize,則新建的是核心線程,如果超過(guò)corePoolSize,則新建的是非核心線程 > > 核心線程默認(rèn)情況下會(huì)一直存活在線程池中,即使這個(gè)核心線程啥也不干(閑置狀態(tài))。 > > 如果指定ThreadPoolExecutor的allowCoreThreadTimeOut這個(gè)屬性為true,那么核心線程如果不干活(閑置狀態(tài))的話,超過(guò)一定時(shí)間(時(shí)長(zhǎng)下面參數(shù)決定),就會(huì)被銷毀掉 > > 很好理解吧,正常情況下你不干活我也養(yǎng)你,因?yàn)槲铱傆杏玫侥愕臅r(shí)候,但有時(shí)候特殊情況(比如我自己都養(yǎng)不起了),那你不干活我就要把你干掉了
int maximumPoolSize
> 該線程池中**線程總數(shù)最大值** > > 線程總數(shù) = 核心線程數(shù) + 非核心線程數(shù)。核心線程在上面解釋過(guò)了,這里說(shuō)下非核心線程: > > 不是核心線程的線程(別激動(dòng),把刀放下...),其實(shí)在上面解釋過(guò)了
long keepAliveTime
> 該線程池中**非核心線程閑置超時(shí)時(shí)長(zhǎng)** > > 一個(gè)非核心線程,如果不干活(閑置狀態(tài))的時(shí)長(zhǎng)超過(guò)這個(gè)參數(shù)所設(shè)定的時(shí)長(zhǎng),就會(huì)被銷毀掉 > > 如果設(shè)置allowCoreThreadTimeOut = true,則會(huì)作用于核心線程
TimeUnit unit
> keepAliveTime的單位,TimeUnit是一個(gè)枚舉類型,其包括: > > 1. NANOSECONDS : 1微毫秒 = 1微秒 / 1000 > 2. MICROSECONDS : 1微秒 = 1毫秒 / 1000 > 3. MILLISECONDS : 1毫秒 = 1秒 /1000 > 4. SECONDS : 秒 > 5. MINUTES : 分 > 6. HOURS : 小時(shí) > 7. DAYS : 天
BlockingQueue
> 該線程池中的任務(wù)隊(duì)列:維護(hù)著等待執(zhí)行的Runnable對(duì)象 > > 當(dāng)所有的核心線程都在干活時(shí),新添加的任務(wù)會(huì)被添加到這個(gè)隊(duì)列中等待處理,如果隊(duì)列滿了,則新建非核心線程執(zhí)行任務(wù) > > 常用的workQueue類型: > > 1. **SynchronousQueue:**這個(gè)隊(duì)列接收到任務(wù)的時(shí)候,會(huì)直接提交給線程處理,而不保留它如果所有線程都在工作怎么辦?那就新建一個(gè)線程來(lái)處理這個(gè)任務(wù)!所以為了保證不出現(xiàn)<線程數(shù)達(dá)到了maximumPoolSize而不能新建線程>的錯(cuò)誤,使用這個(gè)類型隊(duì)列的時(shí)候,maximumPoolSize一般指定成Integer.MAX_VALUE,即無(wú)限大 > > 2. **LinkedBlockingQueue:**這個(gè)隊(duì)列接收到任務(wù)的時(shí)候,如果當(dāng)前線程數(shù)小于核心線程數(shù),則新建線程(核心線程)處理任務(wù);如果當(dāng)前線程數(shù)等于核心線程數(shù),則進(jìn)入隊(duì)列等待。由于這個(gè)隊(duì)列沒(méi)有最大值限制,即所有超過(guò)核心線程數(shù)的任務(wù)都將被添加到隊(duì)列中,這也就導(dǎo)致了maximumPoolSize的設(shè)定失效,因?yàn)榭偩€程數(shù)永遠(yuǎn)不會(huì)超過(guò)corePoolSize > > 3. **ArrayBlockingQueue:**可以限定隊(duì)列的長(zhǎng)度,接收到任務(wù)的時(shí)候,如果沒(méi)有達(dá)到corePoolSize的值,則新建線程(核心線程)執(zhí)行任務(wù),如果達(dá)到了,則入隊(duì)等候,如果隊(duì)列已滿,則新建線程(非核心線程)執(zhí)行任務(wù),又如果總線程數(shù)到了maximumPoolSize,并且隊(duì)列也滿了,則發(fā)生錯(cuò)誤 > > 4. **DelayQueue:**隊(duì)列內(nèi)元素必須實(shí)現(xiàn)Delayed接口,這就意味著你傳進(jìn)去的任務(wù)必須先實(shí)現(xiàn)Delayed接口。這個(gè)隊(duì)列接收到任務(wù)時(shí),首先先入隊(duì),只有達(dá)到了指定的延時(shí)時(shí)間,才會(huì)執(zhí)行任務(wù)
ThreadFactory threadFactory
> 創(chuàng)建線程的方式,這是一個(gè)接口,你new他的時(shí)候需要實(shí)現(xiàn)他的`Thread newThread(Runnable r)`方法,一般用不上,**這是星期六,休息** > > 但我還是說(shuō)一句吧(把槍放下...) > > 小伙伴應(yīng)該知道AsyncTask是對(duì)線程池的封裝吧?那就直接放一個(gè)AsyncTask新建線程池的threadFactory參數(shù)源碼吧: > > ``` > new ThreadFactory() { > private final AtomicInteger mCount = new AtomicInteger(1); > > public Thread new Thread(Runnable r) { > return new Thread(r,"AsyncTask #" + mCount.getAndIncrement()); > } > } > ``` > 這么簡(jiǎn)單?就給線程起了個(gè)名?!對(duì)啊,所以說(shuō)這是星期六啊,別管他了,雖然我已經(jīng)強(qiáng)迫你們看完了...
RejectedExecutionHandler handler
> 這玩意兒就是拋出異常專用的,比如上面提到的兩個(gè)錯(cuò)誤發(fā)生了,就會(huì)由這個(gè)handler拋出異常,你不指定他也有個(gè)默認(rèn)的 > > 拋異常能拋出什么花樣來(lái)?所以這個(gè)星期天不管了,一邊去,根本用不上
新建一個(gè)線程池的時(shí)候,一般只用5個(gè)參數(shù)的構(gòu)造函數(shù)。
向ThreadPoolExecutor添加任務(wù)那說(shuō)了這么多,你可能有疑惑,我知道new一個(gè)ThreadPoolExecutor,大概知道各個(gè)參數(shù)是干嘛的,可是我new完了,怎么向線程池提交一個(gè)要執(zhí)行的任務(wù)啊?
通過(guò)ThreadPoolExecutor.execute(Runnable command)方法即可向線程池內(nèi)添加一個(gè)任務(wù)
ThreadPoolExecutor的策略上面介紹參數(shù)的時(shí)候其實(shí)已經(jīng)說(shuō)到了ThreadPoolExecutor執(zhí)行的策略,這里給總結(jié)一下,當(dāng)一個(gè)任務(wù)被添加進(jìn)線程池時(shí):
線程數(shù)量未達(dá)到corePoolSize,則新建一個(gè)線程(核心線程)執(zhí)行任務(wù)
線程數(shù)量達(dá)到了corePools,則將任務(wù)移入隊(duì)列等待
隊(duì)列已滿,新建線程(非核心線程)執(zhí)行任務(wù)
隊(duì)列已滿,總線程數(shù)又達(dá)到了maximumPoolSize,就會(huì)由上面那位星期天(RejectedExecutionHandler)拋出異常
常見(jiàn)四種線程池如果你不想自己寫一個(gè)線程池,那么你可以從下面看看有沒(méi)有符合你要求的(一般都?jí)蛴昧?,如果有,那么很好你直接用就行了,如果沒(méi)有,那你就老老實(shí)實(shí)自己去寫一個(gè)吧
Java通過(guò)Executors提供了四種線程池,這四種線程池都是直接或間接配置ThreadPoolExecutor的參數(shù)實(shí)現(xiàn)的,下面我都會(huì)貼出這四種線程池構(gòu)造函數(shù)的源碼,各位大佬們一看便知!
來(lái),走起:
CachedThreadPool()可緩存線程池:
線程數(shù)無(wú)限制
有空閑線程則復(fù)用空閑線程,若無(wú)空閑線程則新建線程
一定程序減少頻繁創(chuàng)建/銷毀線程,減少系統(tǒng)開(kāi)銷
創(chuàng)建方法:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
源碼:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }
通過(guò)我上面行云流水談笑風(fēng)生天馬行空滔滔不絕的對(duì)各種參數(shù)的說(shuō)明,這個(gè)源碼你肯定一眼就看懂了,想都不用想(下面三種一樣啦)
FixedThreadPool()定長(zhǎng)線程池:
可控制線程最大并發(fā)數(shù)(同時(shí)執(zhí)行的線程數(shù))
超出的線程會(huì)在隊(duì)列中等待
創(chuàng)建方法:
//nThreads => 最大線程數(shù)即maximumPoolSize ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads); //threadFactory => 創(chuàng)建線程的方法,這就是我叫你別理他的那個(gè)星期六!你還看! ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
源碼:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
2個(gè)參數(shù)的構(gòu)造方法源碼,不用我貼你也知道他把星期六放在了哪個(gè)位置!所以我就不貼了,省下篇幅給我扯皮
ScheduledThreadPool()定長(zhǎng)線程池:
支持定時(shí)及周期性任務(wù)執(zhí)行。
創(chuàng)建方法:
//nThreads => 最大線程數(shù)即maximumPoolSize ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);
源碼:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } //ScheduledThreadPoolExecutor(): public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }SingleThreadExecutor()
單線程化的線程池:
有且僅有一個(gè)工作線程執(zhí)行任務(wù)
所有任務(wù)按照指定順序執(zhí)行,即遵循隊(duì)列的入隊(duì)出隊(duì)規(guī)則
創(chuàng)建方法:
ExecutorService singleThreadPool = Executors.newSingleThreadPool();
源碼:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); }
還有一個(gè)Executors.newSingleThreadScheduledExecutor()結(jié)合了3和4,就不介紹了,基本不用。
結(jié)語(yǔ)墻裂建議各位看完本文一定要實(shí)際動(dòng)手去敲一遍都驗(yàn)證一遍,這樣才能很好的掌握知識(shí)
動(dòng)手做,永遠(yuǎn)是學(xué)習(xí)的最好的方式!
end
更多內(nèi)容歡迎訪問(wèn)我的主頁(yè)或我的博客
如果我的文章確實(shí)有幫助到你,請(qǐng)不要忘了點(diǎn)一下文末的"?"讓他變成"?"
作為小菜鳥難免很多地方理解不到位,文中若有錯(cuò)誤請(qǐng)直(bu)接(yao)指(ma)出(wo)
寫作不易!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67049.html
摘要:也是自帶的一個(gè)基于線程池設(shè)計(jì)的定時(shí)任務(wù)類。其每個(gè)調(diào)度任務(wù)都會(huì)分配到線程池中的一個(gè)線程執(zhí)行,所以其任務(wù)是并發(fā)執(zhí)行的,互不影響。 原創(chuàng)不易,如需轉(zhuǎn)載,請(qǐng)注明出處https://www.cnblogs.com/baixianlong/p/10659045.html,否則將追究法律責(zé)任?。?! 一、在JAVA開(kāi)發(fā)領(lǐng)域,目前可以通過(guò)以下幾種方式進(jìn)行定時(shí)任務(wù) 1、單機(jī)部署模式 Timer:jdk中...
摘要:高并發(fā)系列第篇文章。簡(jiǎn)單的說(shuō),在使用了線程池之后,創(chuàng)建線程變成了從線程池中獲取一個(gè)空閑的線程,然后使用,關(guān)閉線程變成了將線程歸還到線程池。如果調(diào)用了線程池的方法,線程池會(huì)提前把核心線程都創(chuàng)造好,并啟動(dòng)線程池允許創(chuàng)建的最大線程數(shù)。 java高并發(fā)系列第18篇文章。 本文主要內(nèi)容 什么是線程池 線程池實(shí)現(xiàn)原理 線程池中常見(jiàn)的各種隊(duì)列 自定義線程創(chuàng)建的工廠 常見(jiàn)的飽和策略 自定義飽和策略 ...
摘要:前言從號(hào)開(kāi)始在寫下第一篇文章說(shuō)是筆記還差不多,驚奇地收到有人收藏我的文章的消息,覺(jué)得有點(diǎn)開(kāi)心。突然腦子抽到想爬下里標(biāo)簽下的文章有多少,哪篇被收藏最多,哪篇被點(diǎn)贊最多。。?,F(xiàn)在和大家分享下,收藏量前的文章,被那么多人收藏應(yīng)該是篇值得看的文章。 前言 從18號(hào)開(kāi)始在sf寫下第一篇文章(說(shuō)是筆記還差不多),驚奇地收到有人收藏我的文章的消息,覺(jué)得有點(diǎn)開(kāi)心。突然腦子抽到想爬下sf里JAVA標(biāo)簽下...
摘要:如果什么事都沒(méi)得做,它也不會(huì)死循環(huán),它會(huì)將線程休眠起來(lái),直到下一個(gè)事件來(lái)了再繼續(xù)干活,這樣的一個(gè)線程稱之為線程。而請(qǐng)求處理邏輯既可以使用單獨(dú)的線程池進(jìn)行處理,也可以跟放在讀寫線程一塊處理。 Netty到底是什么 從HTTP說(shuō)起 有了Netty,你可以實(shí)現(xiàn)自己的HTTP服務(wù)器,F(xiàn)TP服務(wù)器,UDP服務(wù)器,RPC服務(wù)器,WebSocket服務(wù)器,Redis的Proxy服務(wù)器,MySQL的P...
閱讀 893·2021-11-23 09:51
閱讀 1107·2021-11-15 17:57
閱讀 1674·2021-09-22 15:24
閱讀 820·2021-09-07 09:59
閱讀 2234·2019-08-29 15:10
閱讀 1857·2019-08-29 12:47
閱讀 760·2019-08-29 12:30
閱讀 3381·2019-08-26 13:51