一、ThreadLocal
https://www.jianshu.com/p/3c5d7f09dfbd
InheritableThreadLocal:解決父子線程之間ThreadLocal傳遞問題
二、線程池
1. 線程池的概念:
線程池就是首先創建一些線程,它們的集合稱為線程池。使用線程池可以很好地提高性能,線程池在系統啟動時即創建大量空閑的線程,程序將一個任務傳給線程池,線程池就會啟動一條線程來執行這個任務,執行結束以后,該線程並不會死亡,而是再次返回線程池中成為空閑狀態,等待執行下一個任務。
2. 線程池的工作機制
2.1 在線程池的編程模式下,任務是提交給整個線程池,而不是直接提交給某個線程,線程池在拿到任務后,就在內部尋找是否有空閑的線程,如果有,則將任務交給某個空閑的線程。
2.1 一個線程同時只能執行一個任務,但可以同時向一個線程池提交多個任務。
3. 使用線程池的原因:
多線程運行時間,系統不斷的啟動和關閉新線程,成本非常高,會過渡消耗系統資源,以及過渡切換線程的危險,從而可能導致系統資源的崩潰。這時,線程池就是最好的選擇了。
4. 4種常見的線程池
4.1 Executors.newCacheThreadPool()
可緩存線程池,先查看池中有沒有以前建立的線程,如果有,就直接使用。如果沒有,就建一個新的線程加入池中,緩存型池子通常用於執行一些生存期很短的異步型任務
線程池為無限大,當執行當前任務時上一個任務已經完成,會復用執行上一個任務的線程,而不用每次新建線程
4.2 Executors.newFixedThreadPool(int n)
創建一個可重用固定個數的線程池,以共享的無界隊列方式來運行這些線程。
定長線程池的大小最好根據系統資源進行設置。如Runtime.getRuntime().availableProcessors()
4.3 Executors.newScheduledThreadPool(int n)
創建一個定長線程池,支持定時及周期性任務執行
4.4 Executors.newSingleThreadExecutor()
創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
三、ThreadLocal結合線程池使用
public class TestThreadLocal {
private ThreadLocal<Integer> local = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
public void getAndAdd() {
Integer integer = local.get();
System.out.println(Thread.currentThread().getName() + ": (get and add local) thread values is:"+integer);
local.set(integer+1);
}
public void get() {
System.out.println(Thread.currentThread().getName() + ": (get) local thread values is:"+local.get());
}
public void clear() {
local.remove();
}
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(1);
final TestThreadLocal testThreadLocal = new TestThreadLocal();
Runnable runnable = () -> {
testThreadLocal.getAndAdd();
testThreadLocal.get();
testThreadLocal.clear();
};
for (int i = 0; i < 100; i++) {
service.submit(runnable);
}
}
}
1
五、線程池原理



阻塞隊列
用來創建線程,一般有三種選擇的阻塞隊列。
ArrayBlockingQueue: 這是一個由數組實現的容量固定的有界阻塞隊列.
SynchronousQueue: 沒有容量,不能緩存數據;每個put必須等待一個take; offer()的時候如果沒有另一個線程在poll()或者take()的話返回false。
LinkedBlockingQueue: 這是一個由單鏈表實現的默認無界的阻塞隊列。LinkedBlockingQueue提供了一個可選有界的構造函數,而在未指明容量時,容量默認為Integer.MAX_VALUE。
handler:拒絕處理策略
當阻塞隊列滿了且線程數量大於最大線程數就會采用拒絕處理策略,四種策略為:
ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調用線程直接處理該任務(可能為主線程Main),保證每個任務執行完畢

五.如何合理配置線程池的大小
本節來討論一個比較重要的話題:如何合理配置線程池大小,僅供參考。
一般需要根據任務的類型來配置線程池大小:
如果是CPU密集型任務,就需要盡量壓榨CPU,參考值可以設為 NCPU+1
如果是IO密集型任務,參考值可以設置為2*NCPU
講的很詳細:Java線程池實現原理及其在美團業務中的實踐
六.線程池的狀態


Work線程的添加

Work線程的執行

Work線程的回收
七.實際問題及方案思考
7.1 解決實際問題

7.2 線程池的參數並不好配置
