聊聊Java線程池那些事

為什么使用線程池

線程池作用就是通過限制系統(tǒng)中執(zhí)行線程的數(shù)量從而達到優(yōu)化資源分配的目的。

控制執(zhí)行線程的數(shù)量

假如現(xiàn)在有一個工作臺,上面只能有5個人作業(yè).

使用鎖

Java引入了Semaphore的一個類,稱為信號量.可以指定開放多少把

事例代碼


public class WorkPlace {
    
    private static Semaphore semaphore = new Semaphore(5);
    
    public static void main(String[] args) throws Exception {
        /**
         * 模擬10個工人去申請使用工作臺作業(yè)
         */
        for (int i = 0; i < 10; i++) {
            new Thread() {
                public void run() {
                    work();
                };
            }.start();
        }
    }
    
    
    /*
     * 工作臺的作業(yè)情景,每次只能有5個工人在上面作業(yè)
     */
    public static void work() {
        try {
            semaphore.acquire();    //要工作了,獲取一把鎖
            System.out.println(Thread.currentThread().getName() + "正在工作!");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "工作完畢!");
        semaphore.release();    //工作完畢,釋放這把鎖
    }
}

這樣就保證了每次最多有5個工人可以在上面作業(yè)

使用線程池實現(xiàn)

Java線程池類型

  • newSingleThreadExecutor

線程池中只有一個線程執(zhí)行,相當(dāng)于單線程.但是如果線程掛了之后(異常結(jié)束等),會重新啟動一個線程替原來的線程執(zhí)行下去

  • newFixedThreadPool

線程池的大小是固定的.每次提交一個任務(wù)就會創(chuàng)建一個線程,直到線程達到線程池的最大限制,里面有一個任務(wù)隊列去維護未執(zhí)行的任務(wù),當(dāng)有空閑的線程的時候就會到任務(wù)隊列里面去取.

  • newCachedThreadPool

線程池中的線程是可緩存的.如果線程池的大小超過所需執(zhí)行任務(wù)的大小,則系統(tǒng)會回收空閑線程(60秒不執(zhí)行任務(wù)).當(dāng)任務(wù)數(shù)增加時,線程池又可以自動添加新線程來處理任務(wù).并且線程池不做大小的限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。

  • newScheduledThreadPool

線程池不限大小,并且支持任務(wù)定時周期性循環(huán)

事例代碼

public class WorkPlace {
    
    private static Executor executor = Executors.newFixedThreadPool(5);
    // private static Executor executor =  Executors.newScheduledThreadPool(5);//也可以
    
    public static void main(String[] args) throws Exception {
        /**
         * 模擬100個工人去申請使用工作臺作業(yè)
         */
        for (int i = 0; i < 100; i++) {
            executor.execute(new Runnable() {
                
                @Override
                public void run() {
                    work();
                }
            });
        }
    }
    
    /*
     * 工作臺的作業(yè)情景,每次只能有5個工人在上面作業(yè)
     */
    public static void work() {
        try {
            System.out.println(Thread.currentThread().getName() + "正在工作!");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "工作完畢!");
    }
}

簡單剖析Java的線程池類型

通過對方法的追蹤,我們可以看到上面的四種線程池都是來自同一個東西ThreadPoolExecutor
那我們能不能嘗試使用ThreadPoolExecutor這個類來實現(xiàn)線程池呢?下面繼續(xù)...

ThreadPoolExecutor構(gòu)造器參數(shù)

我們通過查看ThreadPoolExecutor類,可以看到有幾個主要的參數(shù).

  • corePoolSize //核心線程數(shù)量
  • maximumPoolSize //最大線程數(shù)量
  • keepAliveTime //空閑線程存活時間
  • unit //keepAliveTime的單位(時分秒等)
  • workQueue //任務(wù)隊列,用來存放將要執(zhí)行的任務(wù)(Runnable類型)
  • threadFactory //產(chǎn)生線程的方式
  • handler //當(dāng)線程池不能接受任務(wù)時拋出的異常由該對象處理

錯綜復(fù)雜的corePoolSize maximumPoolSize workQueue關(guān)系

關(guān)系
  1. 當(dāng)提交任務(wù)時當(dāng)前啟動的線程總數(shù)小于corePoolSize的時候,每次提交一個任務(wù),都會新建一個線程.
  2. 當(dāng)提交任務(wù)時當(dāng)前啟動的線程總數(shù)大于等于corePoolSize的時候,就會把任務(wù)扔到workQueue里面去,然后新建或者復(fù)用線程,并且保證啟動的線程總數(shù)小于等于maximumPoolSize.
  3. 每當(dāng)一個任務(wù)結(jié)束之后,線程池里面的線程就會從workQueue中取.

maximumPoolSize = 核心線程數(shù)量 + 非核心線程數(shù)量
也容易看出,提交的任務(wù)總數(shù)應(yīng)該小于maximumPoolSize + workQueue的大小
例如:maximumPoolSize = 10,workQueue的大小 = 20
當(dāng)提交31個任務(wù)的時候,所有線程10個全開.然后還有21個任務(wù)需要進入任務(wù)隊列里面等待被取走執(zhí)行,但是任務(wù)隊列的大小只有20,裝不下21.這時候就會拋出RejectedExecutionHandler的異常

事例代碼


public class WorkPlace {
    
    private static AtomicInteger                    count       = new AtomicInteger(0);
                                                                
    private static LinkedBlockingQueue<Runnable>    workQueue   = new LinkedBlockingQueue<>(5);
    private static Executor                         executor    = new ThreadPoolExecutor(5, 5, 1, TimeUnit.SECONDS,
            workQueue, new ThreadFactory() {
                
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setName("線程" + count.getAndIncrement());
                    return thread;
                }
            });
            
    public static void main(String[] args) throws Exception {
        /**
         * 模擬10個工人去申請使用工作臺作業(yè)
         */
        for (int i = 0; i < 10; i++) {
            executor.execute(new Runnable() {
                
                @Override
                public void run() {
                    work();
                }
            });
        }
    }
    
    /*
     * 工作臺的作業(yè)情景,每次只能有5個工人在上面作業(yè)
     */
    public static void work() {
        try {
            System.out.println(Thread.currentThread().getName() + "正在工作!");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "工作完畢!");
    }
}

同樣,上面的代碼也能夠?qū)崿F(xiàn)前面的效果
當(dāng)我們把10個工人修改成11個工人的時候,程序就拋出RejectedExecutionHandler異常了
AtomicIntegerint的另一個包裝類,不過是線程安全的.因為我們不清楚同時會有多少個對象去調(diào)用ThreadFactorynewThread方法,所以為了保證編號的正確性,所以使用AtomicInteger代替int

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,268評論 2 375

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