ThreadLocal與線程池共用時可能出現的的兩個問題

直接先線程池中獲取主線程或非線程池中的ThreadLocal設置的變量的值

例如

    private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor(
            50,
            80,
            8000,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(600)
    );
    public static void main(String[] args) {
        ThreadLocal<String> threadLocal = new ThreadLocal<>();
        threadLocal.set("userId115807");
        syncAccessPool.execute(()->{
            System.out.println(threadLocal.get());
        });
    }

最後打印的結果是null


解決辦法:真實使用中相信大家不會這麼使用的,但是我出錯主要是因爲使用了封裝的方法,封裝的方法中使用了ThreadLocal,這種情況下要先從ThreadLocal中獲取到方法中,再設置到線程池

線程池中使用了ThreadLocal設置了值但是使用完後並未移除造成內存飆升或OOM

public class ThreadLocalOOM {
    static class LocalVariable{
        private Long[] a = new Long[1024*1024];
    }
    private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor(
            50,
            80,
            8000,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(600)
    );
    final static  ThreadLocal<LocalVariable> threadLocal = new ThreadLocal<LocalVariable>();


    public static void main(String[] args) throws InterruptedException {

        Thread.sleep(10000);
        for (int i=0;i<100;i++){
            syncAccessPool.execute(()->{
                threadLocal.set(new LocalVariable());
                System.out.println("use local variable");
            });
            Thread.sleep(1000);
        }
        System.out.println("pool execute over");
    }
}

這個程序使用jconsole程序觀察到的內存變化爲

在使用完之後remove之後的內存變化

   public static void main(String[] args) throws InterruptedException {

        for (int i=0;i<100;i++){
            syncAccessPool.execute(()->{
                threadLocal.set(new LocalVariable());
                System.out.println("use local variable");
                threadLocal.remove();
            });
            Thread.sleep(1000);
        }
        System.out.println("pool execute over");
    }

內存相比之前降低了幾倍。這個原因就是沒有remove,線程池中所有存在的線程都會持有這個本地變量,導致內存暴漲。如果將private Long[] a = new Long[1024*1024]; 擴大可能就會很快拋出OOM異常

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