ThreadLocal子线程共享

简介: ThreadLocal子线程共享

世人缺乏的是毅力,而非气力。——雨果

昨天聊了ThreadLocal可以用作单个线程中变量共享

其底层实现其实就是个Map,用线程作为key,不信可以看这部分源码:

/**
 * Returns the value in the current thread's copy of this
 * thread-local variable.  If the variable has no value for the
 * current thread, it is first initialized to the value returned
 * by an invocation of the {@link #initialValue} method.
 *
 * @return the current thread's value of this thread-local
 */
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}


但是这里有个问题,如果是子线程,就访问不到了

我们深入源码看到这里有这么一个函数

/**
 * Method childValue is visibly defined in subclass
 * InheritableThreadLocal, but is internally defined here for the
 * sake of providing createInheritedMap factory method without
 * needing to subclass the map class in InheritableThreadLocal.
 * This technique is preferable to the alternative of embedding
 * instanceof tests in methods.
 */
T childValue(T parentValue) {
    throw new UnsupportedOperationException();
}

该方法在ThreadLocalMap的构造函数被调用,上面的注释说,该方法明显是在子类InheritableThreadLocal中定义的,这里提供这个方法,主要是能让Thread在构造函数中能调用上面说到的InheritableThreadLocalchildValue

可以看到Thread的构造函数中:

简单来说,如果是inheritableThreadLocal,就执行该方法。我们接着往里看ThreadLocalMap的构造方法

这里把ThreadLocalMap中所有的元素遍历出来,拿到key然后执行了childValue方法

这里key其实就是我们的子线程

我们再看InheritableThreadLocalchildValue的实现

他直接把传入的值return了出去(绕来绕去的,这里主要是考虑到如果还有别的行为,方便继承后可以拓展)

然后再将子线程作为的key和父value组成一个新的Entry元素,把它放到map里去

因此它可以在子线程中共享变量,因为它默认的实现就是子线程的key但是存的父值

写个demo测一下:

package com.ruben.study;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
 * ThreadLocal例子
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/23 16:43
 */
public class ThreadLocalDemo {
    private static final ThreadLocal<Long> MY_LONG_THREAD = new ThreadLocal<>();
    private static final ThreadLocal<Long> MY_LONG_INHERITABLE_THREAD = new InheritableThreadLocal<>();
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MY_LONG_THREAD.set(0L);
        MY_LONG_INHERITABLE_THREAD.set(1L);
        // 单线程共享变量
        CompletableFuture.runAsync(() -> {
            // 子线程尝试访问ThreadLocal中的值
            System.out.println(MY_LONG_THREAD.get());
            System.out.println(MY_LONG_INHERITABLE_THREAD.get());
        }).get();
        MY_LONG_THREAD.remove();
        MY_LONG_INHERITABLE_THREAD.remove();
    }
}

可以看到同样的代码,上面的ThreadLocal在子线程中获取不到,而它的实现InheritableThreadLocal就可以

相关文章
|
6月前
|
存储 Java 测试技术
ThreadLocal:线程专属的变量
ThreadLocal:线程专属的变量
69 0
|
调度
线程都有哪些方法?
线程都有哪些方法?
58 0
|
3天前
|
存储 监控 安全
深入理解ThreadLocal:线程局部变量的机制与应用
在Java的多线程编程中,`ThreadLocal`变量提供了一种线程安全的解决方案,允许每个线程拥有自己的变量副本,从而避免了线程间的数据竞争。本文将深入探讨`ThreadLocal`的工作原理、使用方法以及在实际开发中的应用场景。
12 2
|
2月前
|
安全 Java
LinkedBlockingQueue 是线程安全的,为什么会有两个线程都take()到同一个对象了?
LinkedBlockingQueue 是线程安全的,为什么会有两个线程都take()到同一个对象了?
47 0
|
6月前
|
存储 开发框架 安全
【C++ 线程】深入理解C++线程管理:从对象生命周期到线程安全
【C++ 线程】深入理解C++线程管理:从对象生命周期到线程安全
477 0
多线程之Thread类常见方法及线程的状态
多线程之Thread类常见方法及线程的状态
|
6月前
|
存储 安全 Java
【线程本地变量ThreadLocal】—— 每天一点小知识
【线程本地变量ThreadLocal】—— 每天一点小知识
101 0
|
Java API 调度
线程的创建和使用
线程的创建和使用
54 0
|
安全 应用服务中间件
线程数据共享和安全 -ThreadLocal
线程数据共享和安全 -ThreadLocal
85 0
|
存储 Java 数据库连接
【并发技术07】使用ThreadLocal在线程范围内共享数据
【并发技术07】使用ThreadLocal在线程范围内共享数据