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()
ThreadLocal
的get()
方法访问变量时,实际操作的是当前线程的ThreadLocalMap
属性。具体步骤如下:
- 当前线程会首先查找自己的
ThreadLocalMap
。 - 如果找到对应的值,就返回这个值;如果没有找到,则会调用
initialValue()
方法来生成一个默认值,将ThreadLocalMap
value对象返回。
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数据传递?
- 手动传递上下文
InheritableThreadLocal
可继承上下文,InheritableThreadLocal是ThreadLocal子类- 线程池 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();
}
}