TransmittableThreadLocal 解決 線程池線程復用 無法復制 InheritableThreadLocal 的問題.


 

ThreadLoacl,InheritableThreadLocal,原理,以及配合線程池使用的一些坑

 

TransmittableThreadLocal 原理

 

之前為了能讓InheritableThreadLocal 正確傳遞,不得不每次

ExecutorService executor = Executors.newFixedThreadPool(>=[任務線程數]);
或者直接new Thread.

這樣不僅引起性能損耗,並且如果並發上來了,會造成不必要的上下文切換.還必須用信號量做並發控制.
偶然發現 阿里開源 TransmittableThreadLocal 可以解決此問題.
以下來實驗一下

 

/**
 * User: laizhenwei
 * Date: 2018-04-12 Time: 10:07
 * Description:
 */
public class Ttl {

    static ExecutorService executorService = Executors.newFixedThreadPool(1);

    public static void main(String[] args) {
        //子線程每次new 所以會復制線程的InheritableThreadLocal,結果正確
//        withoutThreadPool(10);
        //因線程池復用線程,不會每次new 所以不會更新父線程InheritableThreadLocal 的值,導致結果錯誤
        withThreadPool(10);
    }

    public static void withoutThreadPool(int c){
        for(int i=0;i<c;i++){
            Integer var1 = (int)(Math.random()*100);
            Integer var2 = (int)(Math.random()*100);
            MyContextHolder.set(var1);
            threadRun(var1,var2);
        }
    }

    public static void withThreadPool(int c){
        for(int i=0;i<c;i++){
            Integer var1 = (int)(Math.random()*100);
            Integer var2 = (int)(Math.random()*100);
            MyContextHolder.set(var1);
            threadPoolExecute(var1,var2);
        }
    }

    public static void threadRun(Integer var1,Integer var2){
        new Thread(()->assert1(var1,var2)).start();
    }

    public static void threadPoolExecute(Integer var1,Integer var2){
                executorService.execute(()->assert1(var1,var2));
    }


    public static void assert1(Integer var1,Integer var2){
            System.out.println(MyContextHolder.get()*var2==var1*var2);
    }


    public static class MyContextHolder{

       private static ThreadLocal<Integer> stringThreadLocal = new InheritableThreadLocal<>();

        public static void set(Integer data) {
            stringThreadLocal.set(data);
        }

        public static Integer get() {
            return stringThreadLocal.get();
        }
    }

}
withoutThreadPool(10)輸出結果

withThreadPool(10); 輸出結果

 

解決方式

pom引入

        <!-- https://mvnrepository.com/artifact/com.alibaba/transmittable-thread-local -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>transmittable-thread-local</artifactId>
            <version>2.2.0</version>
        </dependency>

修改MyContextHolder

    public static class MyContextHolder{

        private static ThreadLocal<Integer> stringThreadLocal = new TransmittableThreadLocal<>();

//       private static ThreadLocal<Integer> stringThreadLocal = new InheritableThreadLocal<>();

        public static void set(Integer data) {
            stringThreadLocal.set(data);
        }

        public static Integer get() {
            return stringThreadLocal.get();
        }
    }

修改threadPoolExecute

    public static void threadPoolExecute(Integer var1,Integer var2){
        //使用TransmittableThreadLocal 解決
        executorService.execute(TtlRunnable.get(()->assert1(var1,var2)) );
//                executorService.execute(()->assert1(var1,var2));
    }

運行 withThreadPool(10); 結果

 



 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM