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 {// 线程任务执行之前,把用户信息从主线程传递到子线程@Overridepublic 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();}
}