ThreadLocal搭配線程池使用

ThreadLocal

根據我的理解,ThreadLocal就是爲每個Thread(線程)創建一個對象的copy,根據ThreadLocal的引用在map中獲得相應的對象值,這樣在多個線程同時操作同一個ThreadLocal對象的時候,其並不是操作的原始的對象,而是複製的對象,所以多個線程就不會相互影響了。 注意,主線程和new出來的線程其實是不同的線程,所以主線程對於ThreadLocal的賦值其實是無效的,甚至於靜態代碼塊的操作,都是對新的線程不可見的,所以一般來說,new ThreadLocal的時候可以重寫他的initValue方法,這樣的操作是對新線程可見的

在子線程中獲取ThreadLocal,然後獲得其value,按理來說是不一樣的,但是如果我們把他放到線程池裏面執行呢?一切就有點意思了

public class Local {
private static final ThreadLocal<Person> local = new ThreadLocal<Person>(){
    @Override
    protected Person initialValue() {
        return new Person();
    }
};


public static void main(String[] args) throws InterruptedException {
    ExecutorService pool = Executors.newFixedThreadPool(98)
    for (int i = 0; i < 100;i++) {
        int finalI = i;
        Runnable r = () ->{
            System.out.println(local.get().getName());
            local.get().setName("wang"+ finalI);

        };
        pool.execute(r);
        Thread.sleep(10l);
    }
}
}

定長線程池

定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。

我們可以看到結果是
一片null 只有最後兩行是wang0 和wang1
爲什麼呢?因爲最後2個任務在池隊列等待,然後進去了之後,分配了前兩個線程。而前兩個線程已經處理過一次ThreadLocal了,再次獲取的時候就直接可以獲取之前的值,所以打印出來的就是wang0 ,wang 1

稍微有些常識的人都能看出來,如果繼續在第一個和第二個線程裏寫入 Thread.sleep(1000l); 那麼打印出來的就是wang2 wang3

如果我們將池的大小設置爲96 ,即將執行的Runnable數爲100,去除線程睡眠,那麼 就會有4個線程可以獲得之前已經處理過的ThreadLocal (因爲執行時間很短而且執行任務數目不多,出現一個線程被2次以上覆用的情況幾乎不存在)。打印出來的就會有隨機4個wang +數字

玩完了,所以這兩者結合的時候,雖然不會有線程安全的問題。但是可能會有很明顯的數據複用問題。注意注意

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章