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