天天看點

一個demo讓你徹底了解線程池工作流程

網上關于線程池的八股文太多了我不多說,說了你也記不住,記住了也了解不了,了解了也不會用…

想了很久,終于想出一個demo,加上十個場景,讓你能逐漸了解線程池真正的工作流程

相信我,認真看完這篇文章,你能徹底掌握一個Java核心知識點,不虧

線程池無非就那幾個參數:核心線程、最大線程、回收時間、隊列,沒啥難的,有手就能學廢

我這裡直接上demo,不知道參數啥意思的可以先去隔壁補補課,雖然本文也會提到,但你最好先大概知道點,線程池實作運作機制總結

上才藝

public class ThreadPoolExecutorTest {
    private static final int taskCount = 50;//任務數

    public static void main(String[] args) throws InterruptedException {
        AtomicInteger integer = new AtomicInteger();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                10,//核心線程數
                20,//最大線程數
                5,//非核心回收逾時時間
                TimeUnit.SECONDS,//逾時時間機關
                new ArrayBlockingQueue<>(30)//任務隊列);
        System.out.println("總任務數:" + taskCount);
        long start = System.currentTimeMillis();
        //模拟任務送出
        for (int i = 0; i < taskCount; i++) {
            Thread thread = new Thread(() -> {
                try {
                    Thread.sleep(500);//模拟執行耗時
                    System.out.println("已執行" + integer.addAndGet(1) + "個任務");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            try {
                //注意這裡我try起來了,預設拒絕政策會報錯
                executor.execute(thread);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        long end = 0;
        while (executor.getCompletedTaskCount() < 50) {
            end = System.currentTimeMillis();
        }
        System.out.println("任務總耗時:" + (end - start));
    }
}      

重點來了,我們帶着問題來看demo

如上,new了個線程池,core線程數10,最大線程數20,任務隊列容量30,請聽題!!

問題0:往上述線程池中送出5個任務,任務執行完總耗時多少?

分析:我核心線程數10,也就是說10個線程會長期處于活躍狀态,來任務立馬能執行,5<10,是以5個任務立馬全部執行,多線程并行當然是異步,是以是500ms

一個demo讓你徹底了解線程池工作流程

插個嘴:為什麼不是500而是540,因為代碼執行需要花時間,畢竟是模拟送出任務,并不是真正一瞬間送出完

問題1:送出10個任務,總耗時多少?

依然是500,10個任務和5個任務其實都一樣,沒超過核心線程數,來一個執行一個
一個demo讓你徹底了解線程池工作流程

問題2:送出11個任務,總耗時多少?

1000,别驚訝,這就是很多人沒搞懂線程池機制的關鍵點,雖然隻多了一個任務,但是第11個任務不會馬上執行,因為隊列沒滿,是以前10個任務會立馬執行,而第11個會被扔到隊列中,等有線程空出來了再執行
一個demo讓你徹底了解線程池工作流程

問題3:送出20個任務,總耗時多少?

也是1000,别問為什麼也别杠,今天就是耶稣來了它也是1000,這20個任務,前10個任務來一個執行一個,從第11個到第20個會全部丢進隊列,目前十個任務有任務執行完了,才會從隊列取出執行
一個demo讓你徹底了解線程池工作流程

問題4:送出30個任務,總耗時多少?

當然是1500啦,30/10=3,3*500=1500
一個demo讓你徹底了解線程池工作流程

問題5:送出40個任務,總耗時多少?

當然是2000啦,10+10+10+10,我不想解釋
一個demo讓你徹底了解線程池工作流程

重點來了!!

問題6:送出41個任務,總耗時多少?

也是2000,很多人會認為是1500,11+11+11+8,其實不然,這裡先記下,我後面說,先繼續往下看
一個demo讓你徹底了解線程池工作流程

問題7:送出45個任務,總耗時多少?

1500,沒錯就是1500,15+15+15
一個demo讓你徹底了解線程池工作流程

問題8:送出50個任務,總耗時多少?

1500,20+20+10
一個demo讓你徹底了解線程池工作流程

問題9:送出51個任務,總耗時多少?

也是1500,這個線程池同時最大接收50個任務,因為我沒設定拒絕政策,預設是AbortPolicy,即超出的任務會被丢棄并抛出RejectedExecutionException異常,demo中沒報錯是因為我try了

最後來說剛才的遺留問題,為啥41個任務2000,45個任務就1500??

其實很多人沒把這個搞懂的,後面幾個問題我都寫了個一串加号(這個搞懂,線程池你就算掌握了)

如40個任務時,10+10+10+10,這代表所有任務分4組完成,每組執行10個,因為多線程是異步,是以每組執行時間就等于單個任務執行時間,即500ms,是以40個任務就是500+500+500+500=2000

而41個任務時,是11+11+11+8,是以40個任務也是500+500+500+500=2000(肯定會有小夥伴問,41個任務已經超出了隊列容量,線程池中線程為啥沒達到最大線程數,應該是20+20+1才對啊)

記住一句話

任務數 <= 核心線程數時,線程池中工作線程數 = 任務數

核心線程數 + 隊列容量 < 任務數 <= 最大線程數 + 隊列容量時,工作線程數 = 任務數 - 隊列容量

是以

再來繼續看

41個任務時,41-30=11,執行批次為11+11+11+8,即500+500+500+500=2000,有問題嗎?沒有問題

45個任務時,45-30=15,是以15+15+15,即500+500+500=1500,有問題嗎?沒有問題

50個任務時,50-30=20,20+20+10,即500+500+500=1500,有問題嗎?依然沒有問題

課後留個問題,44個任務耗時多少?

希望你自己去跑一下,别不識擡舉

文末補充個冷知識,核心線程數也可以被回收,ThreadPoolExecutor有個屬性叫 allowCoreThreadTimeOut

一個demo讓你徹底了解線程池工作流程

ThreadPoolExecutor給我們提供了一個public方法allowCoreThreadTimeOut,通過**allowCoreThreadTimeOut( true )**就能設定

一個demo讓你徹底了解線程池工作流程

部落格是今天寫的

demo是昨天想的

頭發是前天想demo時掉的

這是我好幾根頭發換來的demo,家裡有條件的都把demo複制下來跑一跑,沒條件的抄也要抄一遍

完結

撒花

ok我話說完