文章目錄
線程池使用及優勢
只要是new thread,就會產生資源的消耗,就需要GC來回收,多核時代,硬件上已經支持多核心處理多個任務,而不是一個核心進行上下文的切換。想一下spring,需要對象,是不需要new的,因爲是依賴注入,提前在容器裏新建好了。
線程池的3個常用方式
架構說明
線程池的底層就是ThreadPoolExecutor。擴展說明:數組,集合,線程池都有一個屁股後面加s的輔助工具類。
編碼實現
ScheduledThreadPool:是帶調度的線程池,可以執行定時任務。
WorkStealingPool:是java8的新特性。
主要有3種類型的線程池,自己知道是5種就行,加上上面那2種。
java中的第四種(繼承thread、實現runable,實現callable,線程池)使用線程的方式—線程池。特性:一池固定線程,一池一線程,一池多線程,分別對應上面三種,看名字就可以對上了。
池化資源,關閉比使用更重要!
凡是做併發系統,必然有池。
執行結果:不過多少人,最多同時支持5個在線,控制了併發,同時任務被積攢。沒有拒絕。
一池一線程是一池固定線程的特殊情況。代碼如下:
運行結果:
一池多線程,當出現併發的時候,根據處理的情況,彈性新建線程。
執行結果會根據併發和處理情況,新建線程。
看一下源代碼:
底層代碼的核心是ThreadPoolExecutor。
逐一分析:針對固定線程線程池。
線程池的核心:ThreadPoolExecutor和阻塞隊列,阻塞隊列決定了特性。
線程池7大核心參數入門簡介
綜合看一下ThreadPoolExecutor:
可以看到常見的五大參數。實際上是有7個。可以看一下ThreadpoolExecutor的源碼,構造方法有7個參數。
7參構造方法如下:
線程池7大參數深入介紹
核心數:當值窗口,最大數:銀行的最大處理窗口數。空閒線程的存活時間是3.4兩個參數。5是來不及處理的任務的存放區,相當於候客區。6是線程工廠,用默認的即可。7是拒絕策略,當處理窗口全開,然後候客區也滿了,就需要拒絕新的任務的添加了。
具體的觸發邏輯,默認開2個窗口(核心線程數),
線程池的執行邏輯,線程池建立,就會有核心數個線程被創建出來等待任務的提交,核心線程被使用之後,新來任務就放在阻塞隊列中,如果阻塞隊列也滿了,說明業務量激增,線程池會增加線程直到等於max(第二個參數),處理完業務峯值之後,如果增加的線程在規定時間(3.4個參數)內沒有分配到任務,則會被銷燬,釋放資源。如果,業務一直增加,線程數到達了最大,阻塞隊列也滿了,則開始拒絕策略,默認有4種。第六個參數是創建什麼樣的線程,一般用默認的就行。
線程池底層工作原理
線程池的拒絕策略理論講解
是什麼:
拒絕策略有4種:
實際工作中實際使用哪一種線程池
正確答案是:一個都不用。
阿里巴巴手冊:規定不允許new 線程的同時,不允許使用默認的。因爲會oom。這就是不能用的原因!
線程池的手寫改造和拒絕策略
實現下圖的線程池:
2核心數,5最大數,5s的空閒時間,賦初值3的阻塞隊列(不賦初值是21億)。
線程工廠用默認的:
飽和以後的拒絕策略:使用默認的Abort策略。
最終效果如下:
這個線程池支持的最大線程數是(max+阻塞隊列size)8,設置9個線程就爆炸了:
看一下拒絕策略:
默認的這種一旦超出承受能力就報異常,生產肯定不能用。
第二種拒絕策略測試代碼:
運行結果:10個請求沒有爆炸。
類似去銀行,銀行滿了之後,問顧客從哪裏來,可以再回去之前的銀行試試。這就是策略二的調節機制。
最後發現是主線程幫着執行了一個任務。
最後這兩種都是丟棄,個人很不建議使用,不允許丟失請求的。
線程池配置合理線程數
核心線程數,最大線程數如何配置才合理呢?
根據業務去考慮,CPU密集型還是IO密集型。
io密集型的例子:比如不停的從數據庫裏面讀取。
第一種:
第二種:
這裏面說的是最大線程數,核心線程數等於0都可以(緩衝線程池底層的初始值就是0).