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); 结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值