Android | 線程池的使用和簡單原理

參考文獻:

1 簡介

?除了①線程池么抗,使用線程還有三種方式辆影,分別是 ②繼承Thread類 ③實現(xiàn)Runnable接口④實現(xiàn)Callable接口扁达,這三種方式最后都需要新建和銷毀線程。在實際的高并發(fā)場景下反肋,往往線程數(shù)多伤塌,每個線程執(zhí)行任務(wù)耗時短茫负。上面三種新建線程的方式米同,新建和銷毀線程的時間消耗經(jīng)常會比實際執(zhí)行任務(wù)的耗時還要長,導致提交的任務(wù)不能立即響應(yīng)執(zhí)行映砖,并且新建和銷毀線程往往有一定的資源消耗翰撑;其次創(chuàng)建新線程的方式線程缺乏統(tǒng)一管理,容易出現(xiàn)線程阻塞的情況啊央。所以這里我們引入了一種復用線程執(zhí)行任務(wù)的方式-線程池眶诈,減少新建線程的次數(shù)。
?首先說說“任務(wù)”的概念瓜饥,實現(xiàn)Runnable或Callable接口創(chuàng)建的對象只能當做一個可以在線程中運行的任務(wù)逝撬,不是真正意義上的線程,所以最后還需要通過 Thread 來調(diào)用乓土∠艹保可以說任務(wù)是通過線程驅(qū)動從而執(zhí)行的。

2 原理

2.1 內(nèi)部邏輯結(jié)構(gòu)

線程池邏輯結(jié)構(gòu)圖

2.2 核心參數(shù)

線程池核心參數(shù)

?ThreadPoolExecutor類是線程池中最重要的類趣苏,可以通過在該類實例化時配置不同的參數(shù)傳入構(gòu)造器狡相,來實現(xiàn)自定義線程池;

        // 創(chuàng)建線程池對象食磕,通過 構(gòu)造方法 配置核心參數(shù)
   Executor executor = new ThreadPoolExecutor( CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,
                                                TimeUnit.SECONDS, sPoolWorkQueue,sThreadFactory );

        // 構(gòu)造函數(shù)
    public ThreadPoolExecutor (int corePoolSize,int maximumPoolSize,long keepAliveTime,
                               TimeUnit unit,BlockingQueue<Runnable workQueue>,
                               ThreadFactory threadFactory )

2.3 任務(wù)執(zhí)行邏輯

線程池任務(wù)執(zhí)行流程圖

?補充說明:

  • 處理任務(wù)優(yōu)先級:核心線程 > 任務(wù)隊列 > 非核心線程 > 拒絕策略handler尽棕;
  • 非核心線程空閑時間超過存活期keepAliveTime,就會被回收彬伦;一般情況滔悉,核心線程即使閑置也不會被回收伊诵;(除非當allowCoreThreadTimeOut(true)時,keepAliveTime也適用于核心線程)回官;
  • 一般情況曹宴,線程池剛創(chuàng)建時,其中是沒有線程的歉提,只有新任務(wù)到來笛坦,才會創(chuàng)建線程執(zhí)行該任務(wù);

? 對于線程池苔巨、核心線程版扩、非核心線程自己的通俗理解:

? ?線程池看成一個公司,核心線程可以看成是看成是公司的正式員工恋拷,非核心線程可以看成是實習生;無論是正式員工還是實習生在同一時刻只能執(zhí)行一個任務(wù)厅缺。當有新任務(wù)時蔬顾,老板首先找正式員工干活;如果正式員工都在干活時繼續(xù)來新任務(wù)湘捎,那么多余任務(wù)就放到一個任務(wù)隊列里诀豁,等有正式員工閑下來后接著干新任務(wù);如果任務(wù)較多窥妇,超出正式員工能處理的數(shù)量舷胜,這時老板就考慮招幾個實習生來干活,實習生處理任務(wù)隊列滿了之后新來的任務(wù)活翩。如果任務(wù)太多了烹骨,那么老板就不再接單了,拒絕處理新來的任務(wù)材泄。

? ?一般情況沮焕,正式員工有任務(wù)到來就干活,沒任務(wù)就空閑拉宗,不會被裁峦树;實習生有任務(wù)到來就干活,沒任務(wù)就空閑旦事,空閑的時間太長了魁巩,老板不養(yǎng)閑人,就把這個實習生裁了姐浮。

3 基本使用

     // 1.創(chuàng)建線程池,通過配置核心參數(shù)谷遂,從而實現(xiàn)自定義線程池
   Executor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,
                                  TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory);
    // 注:在Java中,已內(nèi)置4種常用線程池卖鲤,下面會詳細說明

        // 2.向線程池提交任務(wù):execute()埋凯,傳入Runnable對象
    threadPool.execute(new Runnable() {
            @Override
            public void run() {
                ... // 線程執(zhí)行任務(wù)
            }
        });

    // 3. 關(guān)閉線程池shutdown() 
  threadPool.shutdown();

?shutdown()shutdownNow()區(qū)別:

  • shutdown():等待正在執(zhí)行任務(wù)的線程執(zhí)行完再關(guān)閉線程池点楼;
  • shutdownNow():不等待立即關(guān)閉;

4 四類常用線程池

?根據(jù)參數(shù)的不同配置白对,Java內(nèi)置了4種常用線程池掠廓,他們的參數(shù)已經(jīng)配置好了:

  • 定長線程池(FixedThreadPool)
  • 定時線程池(ScheduledThreadPool )
  • 緩存線程池(CachedThreadPool)
  • 單例線程池(SingleThreadExecutor)

4.1 定長線程池FixedThreadPool

  • 特點:只有核心線程 & 不會被回收、線程數(shù)固定甩恼、任務(wù)隊列無大小限制蟀瞧;

  • 應(yīng)用場景:控制線程池最大并發(fā)數(shù);

//創(chuàng)建 定長線程池 對象 & 設(shè)置線程池線程數(shù)固定為3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//向線程池提交任務(wù):execute()
fixedThreadPool.execute(() -> System.out.println("定長線程池->執(zhí)行任務(wù)啦"));
//關(guān)閉線程池
fixedThreadPool.shutdown();

4.2 定時線程池ScheduledThreadPool

  • 特點:核心線程數(shù)固定、非核心線程數(shù)無限制(閑時立刻回收)条摸;

  • 應(yīng)用場景:執(zhí)行定時 / 周期性 任務(wù)

//創(chuàng)建 定時線程池 對象 & 設(shè)置線程池核心線程數(shù)固定為5
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//創(chuàng)建好Runnable類線程對象 & 需執(zhí)行的任務(wù)
Runnable task1 = () -> System.out.println("定時線程池->執(zhí)行任務(wù)啦");
// 向線程池提交任務(wù):schedule()
scheduledThreadPool.schedule(task1, 1, TimeUnit.SECONDS); // 延遲1s后執(zhí)行任務(wù)
scheduledThreadPool.scheduleAtFixedRate(task1,10,1000,TimeUnit.MILLISECONDS);// 延遲10ms后悦污、每隔1000ms執(zhí)行任務(wù)
//關(guān)閉線程池
scheduledThreadPool.shutdown();

4.3 緩存線程池CachedThreadPool

  • 特點:只有非核心線程、線程數(shù)無限制钉蒲;靈活回收空閑線程(具備超時機制切端,全部回收時幾乎不占系統(tǒng)資源);無線程可用時新建線程顷啼;
  • 應(yīng)用場景:執(zhí)行數(shù)量多踏枣、耗時少任務(wù)
// 創(chuàng)建 可緩存線程池 對象
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//向線程池提交任務(wù)1:execute()
cachedThreadPool.execute(() -> System.out.println("可緩存線程池-執(zhí)行任務(wù)1"));
//向線程池提交任務(wù)2:execute();復用線程
cachedThreadPool.execute(() -> System.out.println("可緩存線程池-執(zhí)行任務(wù)2"));
//關(guān)閉線程池
cachedThreadPool.shutdown();

4.4 單例線程池SingleThreadExecutor

  • 特點:只有一個核心線程钙蒙,保證所有任務(wù)按順序在一個線程中執(zhí)行茵瀑,不存在線程安全問題;

  • 應(yīng)用場景:適合單線程任務(wù)躬厌;不適合必須使用多線程的耗時任務(wù)马昨,如數(shù)據(jù)庫操作、文件操作等扛施;

//創(chuàng)建 單例線程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
//向線程池提交任務(wù):execute()
singleThreadExecutor.execute(() -> System.out.println("單例線程池-執(zhí)行任務(wù)啦"));
//關(guān)閉線程池
singleThreadExecutor.shutdown();

4.5 對比

四類常見線程池對比

5 總結(jié)

線程池要點思維導圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸿捧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疙渣,更是在濱河造成了極大的恐慌笛谦,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昌阿,死亡現(xiàn)場離奇詭異饥脑,居然都是意外死亡,警方通過查閱死者的電腦和手機懦冰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門灶轰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人刷钢,你說我怎么就攤上這事笋颤。” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵伴澄,是天一觀的道長赋除。 經(jīng)常有香客問我,道長非凌,這世上最難降的妖魔是什么举农? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮敞嗡,結(jié)果婚禮上颁糟,老公的妹妹穿的比我還像新娘。我一直安慰自己喉悴,他們只是感情好棱貌,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著箕肃,像睡著了一般婚脱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勺像,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天障贸,我揣著相機與錄音,去河邊找鬼咏删。 笑死惹想,一個胖子當著我的面吹牛问词,可吹牛的內(nèi)容都是我干的督函。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼激挪,長吁一口氣:“原來是場噩夢啊……” “哼辰狡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起垄分,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤宛篇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后薄湿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叫倍,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年豺瘤,在試婚紗的時候發(fā)現(xiàn)自己被綠了吆倦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡坐求,死狀恐怖蚕泽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桥嗤,我是刑警寧澤须妻,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布仔蝌,位于F島的核電站,受9級特大地震影響荒吏,放射性物質(zhì)發(fā)生泄漏敛惊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一司倚、第九天 我趴在偏房一處隱蔽的房頂上張望豆混。 院中可真熱鬧,春花似錦动知、人聲如沸皿伺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸵鸥。三九已至,卻和暖如春丹皱,著一層夾襖步出監(jiān)牢的瞬間妒穴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工摊崭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留讼油,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓呢簸,卻偏偏與公主長得像矮台,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子根时,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

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

  • 第一部分 來看一下線程池的框架圖蛤迎,如下: 1确虱、Executor任務(wù)提交接口與Executors工具類 Execut...
    壓抑的內(nèi)心閱讀 4,272評論 1 24
  • 概述 JAVA通過多線程的方式實現(xiàn)并發(fā),為了方便線程池的管理替裆,JAVA采用線程池的方式對線線程的整個生命周期進行管...
  • 世事艱辛辆童,從不肯稱我心宜咒。于別人輕而易舉,于我艱難萬分胸遇。求而不得荧呐,然后我假裝自己不求。 我這一生從未好運,我安慰自己...
    九徒閱讀 159評論 0 0
  • 人生倍阐。還有多少事情想去完成概疆,卻一直拖著沒去完成的;有多少想去嘗試峰搪,卻一直沒有鼓起勇氣去嘗試的岔冀;有n多少想去原諒,卻...
    forever_girl閱讀 249評論 0 0
  • 韓劇看起來不用腦概耻,顏值高可以研究里面衣服打扮使套,細致情感說話很貼合日常演員表情到位,讓人無聊不想思考的時候就可以跟劇...
    紫馨雅馨閱讀 494評論 0 0