01-InheritableThreadLocal和TransmittableThreadLocal

01-InheritableThreadLocal和TransmittableThreadLocal

1.ThreadLocal存在的问题

public class TheadTest {

    private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();
    
    /**
     * 当通过父线程创建子线程时,父线程ThreadLocal中的数据不会传递到子线程。
     */
    public static void test01() {
        THREAD_LOCAL.set("123");

        new Thread(() -> {
            System.out.println("==" + THREAD_LOCAL.get()); // ==null
        }).start();

        System.out.println(THREAD_LOCAL.get());
    }
}

2.InheritableThreadLocal

  1. InheritableThreadLocal解决ThreadLocal的问题。
public class TheadTest {

    private static final InheritableThreadLocal<String> INHERITABLE_THREAD_LOCAL = new InheritableThreadLocal<>();

    /**
     * InheritableThreadLocal可以在父线程创建子线程时,将父线程ThreadLocal中的数据拷贝到子线程。
     * 当new Thread()时,InheritableThreadLocal会拷贝线程上下文的数据。
     */
    public static void test02() {
        INHERITABLE_THREAD_LOCAL.set("123");
        new Thread(() -> {
            System.out.println("==" + INHERITABLE_THREAD_LOCAL.get()); // ==123
        }).start();

        System.out.println(INHERITABLE_THREAD_LOCAL.get());
    }
}
  1. InheritableThreadLocal解决ThreadLocal的问题源码分析。

    1. Thread类中有两个ThreadLocal.ThreadLocalMap属性。
    ThreadLocal.ThreadLocalMap threadLocals = null;
    
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    
    1. 线程本地变量的复制在new Thread()中。
    public Thread(Runnable target) {
        this(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        this(group, target, name, stackSize, null, true);
    }
    
    private Thread(ThreadGroup g, Runnable target, String name,
                   long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
    
        // 之前代码省略
        
        // inheritThreadLocals是参数传入的值为true。
        // parent.inheritableThreadLocals,在INHERITABLE_THREAD_LOCAL.set("123");时
        // 进行了初始化,所以parent.inheritableThreadLocals != null为true,
        // 程序会进入到if中,将父线程本地变量表的数据拷贝的子线程中。
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        
        // 之后代码省略
    }
    
    1. parent.inheritableThreadLocals初始化部分代码。
    // 执行set()方法时初始化。
    INHERITABLE_THREAD_LOCAL.set("123");
    
    public void set(T value) {
        Thread t = Thread.currentThread();
        // getMap(t)是核心的一段代码。
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }
    
    // InheritableThreadLocal重写了父类ThreadLocal的getMap()方法,所有返回的是
    // Thread类中inheritableThreadLocals。
    ThreadLocalMap getMap(Thread t) {
        return t.inheritableThreadLocals;
    }
    

3.InheritableThreadLocal存在的问题

public class TheadTest {

    private static final InheritableThreadLocal<String> INHERITABLE_THREAD_LOCAL = new InheritableThreadLocal<>();

    /**
     * 打印输出:
     * 456
     * 子线程第一次执行 123
     * 子线程第二次执行 123
     *
     * InheritableThreadLocal在线程池的环境中,当父线程的本地变量表修改之后,
     * 由父线程创建的子线程的本地变量表不会被修改。
     */
    public static void test03() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1));

        INHERITABLE_THREAD_LOCAL.set("123");
        threadPoolExecutor.execute(() -> {
            System.out.println("子线程第一次执行 " + INHERITABLE_THREAD_LOCAL.get());
        });

        INHERITABLE_THREAD_LOCAL.set("456");
        threadPoolExecutor.execute(() -> {
            System.out.println("子线程第二次执行 " + INHERITABLE_THREAD_LOCAL.get());
        });

        System.out.println(INHERITABLE_THREAD_LOCAL.get());
    }
}

4.TransmittableThreadLocal

  1. 引入依赖。
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>transmittable-thread-local</artifactId>
    <version>2.13.2</version>
</dependency>
  1. TransmittableThreadLocal代码事件。
public class TheadTest {
    
    private static final TransmittableThreadLocal<String> TRANSMITTABLE_THREAD_LOCAL = new TransmittableThreadLocal<>();

    /**
     * 打印输出:
     * 456
     * pool-1-thread-1 -> 123
     * pool-1-thread-1 -> 456
     *
     * TransmittableThreadLocal可以解决InheritableThreadLocal在线程池中子线程本地变量表不更新的问题。
     */
    public static void test04() {
        TRANSMITTABLE_THREAD_LOCAL.set("123");

        ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));
        executorService.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " -> " + TRANSMITTABLE_THREAD_LOCAL.get());
        });

        TRANSMITTABLE_THREAD_LOCAL.set("456");
        executorService.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " -> " + TRANSMITTABLE_THREAD_LOCAL.get());
        });

        System.out.println(TRANSMITTABLE_THREAD_LOCAL.get());
    }
}
posted @ 2022-11-27 10:26  行稳致远方  阅读(129)  评论(0)    收藏  举报