线程上下文-ThreadLocal原理

ThreadLocal主要作用:为每个线程提供独立的变量副本,实现线程间的数据隔离,从而避免多线程环境下的资源共享冲突。

原理

ThreadLocal有个内部类 ThreadLocalMap,顾名思义是个Map结构:key为 ThreadLocal实例,value为线程私有数据。

每个Thread线程对象内部有 ThreadLocalMap 属性,用于存储线程本地变量

public class Thread implements Runnable {


    // ...
    ThreadLocal.ThreadLocalMap threadLocals = null;
    // 下文用到
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    
    // ...
    }

ThreadLocal每次使用都是直接调用get()、set()

ThreadLocalget()方法访问变量时,实际操作的是当前线程的ThreadLocalMap 属性。具体步骤如下:

  • 当前线程会首先查找自己的ThreadLocalMap
  • 如果找到对应的值,就返回这个值;如果没有找到,则会调用initialValue()方法来生成一个默认值,将ThreadLocalMapvalue对象返回。
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    // 当前线程ThreadLocalMap若已初始化直接返回局部变量,
    // 未初始化则初始化后返回
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

每个线程都会创建自己线程独立的ThreadLocalMap ,从而保证数据线程隔离。

内存泄漏ThreadLocalMap的键是弱引用,值不是,可能导致内存泄漏。使用后应调用remove()方法清理。

主、子线程ThreadLocal数据传递?

  1. 手动传递上下文
  2. InheritableThreadLocal可继承上下文,InheritableThreadLocal是ThreadLocal子类
  3. 线程池 TaskDecorator 装饰器,任务执行前后做一些事情(手动传递)
public class BusinessContextDecorator implements TaskDecorator {
    
    // 线程任务执行之前,把用户信息从主线程传递到子线程
    @Override
    public Runnable decorate(Runnable runnable) {
        UserContextInfo userContext = UserContext.getUserContext();
        return () -> {
            try {
                UserContext.setUserContext(userContext);
                runnable.run();
            }finally {
                UserContext.clear();
            }
        };
    }
}

@Configuration
public class ThreadPoolExecutorConfig {

    private static final int CORE_THREAD_SIZE = Runtime.getRuntime().availableProcessors() + 1;

    private static final int MAX_THREAD_SIZE = Runtime.getRuntime().availableProcessors() * 2 + 1;

    private static final int WORK_QUEUE = 1000;

    private static final int KEEP_ALIVE_SECONDS = 60;

    @Bean("taskExecutor")
    public Executor taskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(CORE_THREAD_SIZE);
        executor.setMaxPoolSize(MAX_THREAD_SIZE);
        executor.setQueueCapacity(WORK_QUEUE);
        executor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
        executor.setThreadNamePrefix("task-thread-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        // 新增线程装饰器
        executor.setTaskDecorator(new BusinessContextDecorator());
        executor.initialize();
        return executor;
    }
}

父子数据传递

当创建一个新线程时,会调用Thread类的构造方法,在构造方法中会检查父线程的inheritableThreadLocals是否为空,如果不为空,则会将父线程的inheritableThreadLocals复制到子线程的inheritableThreadLocals中。

每个线程都有自己独立的inheritableThreadLocals实例,保证了线程间数据的隔离。

主子线程上下文隔离互不影响

public class InheritableThreadLocalExample {
    // 创建一个 InheritableThreadLocal 实例
    private static final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) {
        // 在父线程中设置 InheritableThreadLocal 的值
        inheritableThreadLocal.set("Hello from parent thread");

        // 打印父线程中的值
        System.out.println("Parent thread value: " + inheritableThreadLocal.get());

        // 创建子线程
        Thread childThread = new Thread(() -> {
            // 打印子线程中继承的 InheritableThreadLocal 的值
            System.out.println("Child thread value: " + inheritableThreadLocal.get());

            // 在子线程中修改 InheritableThreadLocal 的值
            inheritableThreadLocal.set("Hello from child thread");
            System.out.println("Modified child thread value: " + inheritableThreadLocal.get());
        });

        // 启动子线程
        childThread.start();

        try {
            // 等待子线程执行完毕
            childThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打印父线程中的值,验证父线程的值不受子线程修改的影响
        System.out.println("Parent thread value after child thread modification: " + inheritableThreadLocal.get());

        // 清除 InheritableThreadLocal 的值
        inheritableThreadLocal.remove();
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不进大厂不改名1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值