線程池的前世今生

CPU線程爭搶

線程池是池化技術(shù)的一種實(shí)現(xiàn),用戶對線程做統(tǒng)一的管理亭饵,通過統(tǒng)一的管理來降低資源的消耗與提高資源的利用率溃列。

本文將通過一個(gè)小故事來回顧一下java線程池的前世與今生例证。

P1:上古時(shí)代

對于早期的計(jì)算機(jī)語言,設(shè)計(jì)的基本思路都是通過一個(gè)Main函數(shù)啟動(dòng)冠句,開啟主進(jìn)程轻掩。之后在這個(gè)主進(jìn)程中,再開啟一個(gè)個(gè)工作線程懦底。如果主進(jìn)程掛掉唇牧,那么整個(gè)程序也就終止了。

故事

張某三去飯店吃飯聚唐,需要憑票入場丐重。

張三想進(jìn)去吃飯,門童會在門口用石板刻上張某三杆查,把這塊牌子給張某三扮惦。

到飯點(diǎn)飯店開使?fàn)I業(yè)了,只要有拿到票亲桦,那就可以進(jìn)去了崖蜜,進(jìn)去的時(shí)候門童就把票根砸碎。

這時(shí)票是一次性的客峭,用完就沒了豫领。這家飯店就屬于邀請制,給你發(fā)一張券你能來一次舔琅。

線程的上古使用

從遠(yuǎn)古的jdk1.0開始等恐,就有Thread類與Runnable接口。Thread類也是實(shí)現(xiàn)了Runnable接口备蚓。所以無論是通過繼承一個(gè)Thread類重寫run方法课蔬,還是實(shí)現(xiàn)Runnable接口重寫run方法后,再丟入Thread構(gòu)造器本質(zhì)上都一樣郊尝,都是將這個(gè)任務(wù)賦值給Thread類中的類型為Runnabletarget屬性购笆。

Thread構(gòu)造方法調(diào)用init方法

創(chuàng)建一個(gè)Card類,就相當(dāng)于是故事中的門票虚循。后續(xù)故事中也同樣會使用。在實(shí)際工作中,可以理解為一些特別耗內(nèi)存的大對象横缔、或者耗費(fèi)時(shí)間的io操作或者網(wǎng)絡(luò)請求铺遂。

@Data
class  Card {
    String name;
}

通過Main方法直接執(zhí)行。其中Card對象茎刚,Thread對象都被重復(fù)創(chuàng)建了多次襟锐。所以在上古時(shí)代,這種使用線程的方法是非常麻瓜的膛锭。

public static void main(String[] args) throws InterruptedException {

        Demo demo = new Demo();
        demo.old();// 上古時(shí)代
//      demo.old2();//古代
//      demo.old3();//近代
        System.out.println("demo -> end");
    }

    public void old() throws InterruptedException {
        AtomicInteger times = new AtomicInteger(0);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Card card = new Card();
                card.setName("張某三特邀貴賓" + times.incrementAndGet());
                System.out.println(Thread.currentThread().getName()+card.getName());
            }).start();
        }
        Thread.sleep(100);
        System.out.println("門票創(chuàng)建"+times.get()+"次");
    }

從打印的結(jié)果也可以看到粮坞,每一次都是一個(gè)新的線程在執(zhí)行任務(wù)。


demo1執(zhí)行結(jié)果

P2:古代

故事2.0

張某三又去這家飯店吃飯初狰,同樣需要憑票入場莫杈。

門童在門口用石板刻上了店鋪高級vip,把這塊牌給到了張某三奢入。

這樣一來筝闹,只要飯店不倒閉,張某三就能憑票進(jìn)場腥光。

等飯店到了飯點(diǎn)開始營業(yè)关顷,張某三憑票進(jìn)場,吃完之后又把票塞進(jìn)編織袋好好保存武福,放在家里貢了起來议双。

這塊號牌此時(shí)就類似于丹書鐵券、免死金牌捉片,父傳子子傳孫平痰,出入這種高級場所有牌就行,屬于高級會員制界睁。

線程的古代使用方式

public void old2() throws InterruptedException {
        AtomicInteger times = new AtomicInteger(0);
        Card card = new Card();
        card.setName("張某三VIP"+times.incrementAndGet());
        Runnable eat = () -> System.out.println(Thread.currentThread().getName()+card.getName());
        LinkedBlockingDeque<Runnable> eats = new LinkedBlockingDeque<>();
        for (int i = 0; i< 10; i++) {
            eats.add(eat);
        }

        new Thread(()->{
            //線程死循環(huán), 模擬線程不退出, 一直會嘗試去獲取任務(wù)
            AtomicInteger eatTimes = new AtomicInteger(0);
            for (;;) {
                do {
                    try {
                        eats.take().run();
                        Thread.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } while (eatTimes.incrementAndGet() < 10);
                break;
            }
        }).start();

        Thread.sleep(100);
        System.out.println("門票創(chuàng)建"+times.get()+"次");
    }

從執(zhí)行結(jié)果可以看到觉增。耗時(shí)的Card只被新建了一次,Thread線程也只被創(chuàng)建了一次翻斟。說明已經(jīng)共用了線程與對象逾礁。從日志看到,也確實(shí)只有一個(gè)線程Thread-0執(zhí)行任務(wù)访惜。

方案就是一直讓線程執(zhí)行死循環(huán)等待嘹履,從任務(wù)隊(duì)列中取任務(wù)。更高級的操作應(yīng)該是讓線程在沒有任務(wù)時(shí)休眠债热,而不是一直爭搶CPU時(shí)間片砾嫉,當(dāng)然這些功能在近代jdk1.5中已經(jīng)實(shí)現(xiàn)。

古代線程使用方法

P3:近代

故事3.0

張某三又去這家飯店吃飯窒篱,需要憑手牌入場焕刮。

門童給你一塊手牌舶沿,手牌上只寫了39號。

飯店開始營業(yè)之后配并,張某三吃完飯叼著牙簽出來括荡,看到李某四餓的骨瘦嶙峋,餓的好幾天沒吃飯了溉旋。

于是張某三一發(fā)善心畸冲,轉(zhuǎn)手100塊錢就把這個(gè)手牌賣給了李某四。

李某四拿著手牌观腊,門童驗(yàn)明真?zhèn)我叵校_實(shí)是他們飯店發(fā)出去的手牌,也就讓李某四進(jìn)去了梧油。(李某四吃完飯苫耸,沒有錢付餐費(fèi),這個(gè)時(shí)候飯店把李某四catch住婶溯,把手牌也順便給銷毀了鲸阔,這部分就屬于線程異常時(shí)的處理,有機(jī)會另開一篇聊聊)

近代使用方式

單線程的復(fù)用并不優(yōu)雅迄委,對于內(nèi)部的執(zhí)行邏輯褐筛,管理并不方便。所以在jdk1.5之后叙身,JDK提供了ExecutorService類渔扎,實(shí)現(xiàn)了線程池的功能。當(dāng)然我們用的最多信轿,問的最多的還是ThreadPoolExecutor晃痴。

public void old3() throws InterruptedException {
        ExecutorService shop = Executors.newSingleThreadExecutor();
        AtomicInteger times = new AtomicInteger(0);
        Card card = new Card();
        card.setName("張某三手牌"+times.incrementAndGet());
        Runnable eat = () -> System.out.println(Thread.currentThread().getName()+card.getName());
        for (int i = 0; i < 10 ; i++) {
            shop.execute(eat);
        }
        Thread.sleep(100);
        System.out.println("=======張某三完事=========");
        // 轉(zhuǎn)賣手牌
        card.setName(card.getName().replace("張某三", "李某四"));

        for (int i = 0; i < 10 ; i++) {
            shop.execute(eat);
        }
        Thread.sleep(100);
        System.out.println("門票創(chuàng)建"+times.get()+"次");
    }

創(chuàng)建了一個(gè)單線程的線程池,因此只有一個(gè)線程會執(zhí)行任務(wù)财忽。通過線程的命名方式也被改寫為pool name+thread name倘核。

耗時(shí)的Card只被創(chuàng)建了一次,Thread的創(chuàng)建被封裝進(jìn)了線程池中即彪,并且同一個(gè)線程可以執(zhí)行多種任務(wù)紧唱。另外,線程池也提供了比較豐富的API對線程池的狀態(tài)做管理隶校。

近代線程池的使用

P4:現(xiàn)代

最近幾年漏益,慢慢在網(wǎng)上可以看到關(guān)于線程監(jiān)控方面的文章。說明當(dāng)前對線程池的需求也不僅僅局限在用這一方面深胳。對線程的管理绰疤,或者是對線程的精細(xì)化管理將成為重點(diǎn)。

不過在國內(nèi)看到的文章大都是基于美團(tuán)技術(shù)文章的實(shí)現(xiàn)舞终。更詳細(xì)的可以看寫美團(tuán)的文章轻庆,也可以在網(wǎng)上搜索下相關(guān)的博文癣猾。

https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市余爆,隨后出現(xiàn)的幾起案子煎谍,更是在濱河造成了極大的恐慌,老刑警劉巖龙屉,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異满俗,居然都是意外死亡转捕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門唆垃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來五芝,“玉大人,你說我怎么就攤上這事辕万∈嗖剑” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵渐尿,是天一觀的道長醉途。 經(jīng)常有香客問我,道長砖茸,這世上最難降的妖魔是什么隘擎? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮凉夯,結(jié)果婚禮上货葬,老公的妹妹穿的比我還像新娘。我一直安慰自己劲够,他們只是感情好震桶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著征绎,像睡著了一般蹲姐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炒瘸,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天淤堵,我揣著相機(jī)與錄音,去河邊找鬼顷扩。 笑死拐邪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的隘截。 我是一名探鬼主播扎阶,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼汹胃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了东臀?” 一聲冷哼從身側(cè)響起着饥,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惰赋,沒想到半個(gè)月后宰掉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赁濒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年轨奄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拒炎。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挪拟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出击你,到底是詐尸還是另有隱情玉组,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布丁侄,位于F島的核電站惯雳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏绒障。R本人自食惡果不足惜吨凑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望户辱。 院中可真熱鬧鸵钝,春花似錦、人聲如沸庐镐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽必逆。三九已至怠堪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間名眉,已是汗流浹背粟矿。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留损拢,地道東北人陌粹。 一個(gè)月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像福压,于是被迫代替她去往敵國和親掏秩。 傳聞我的和親對象是個(gè)殘疾皇子或舞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

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