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



    
    
  • 相关阅读:
    Git的常用命令收集
    【Android界面实现】使用ScrollingTabsView实现有滑动标签的ViewPager效果
    android ViewPager中页面延迟加载的实现
    android 项目快速修改包名
    Json详细使用(二) 序列话和反序列话
    Json的详细使用(一)处理数组/List/Map
    C++ stack around variable....错误
    刷题-滑动窗口类型 求连续数组最大值
    C# 动态绘制扇形图;
    C# livechart使用
  • 原文地址:https://www.cnblogs.com/sweetchildomine/p/8807059.html
Copyright © 2020-2023  润新知