一、场景
这里就直接介绍最复杂的应用场景
多个独立的线程池嵌套使用,上下文传递及清除ThreadLocal值,此处就简单以ThreadLocal,InheritableThreadLocal,TransmittableThreadLocal(阿里开源组件)为例介绍
二、线程副本应用场景及比较
ThreadLocal
该线程副本对象只适用于一次性线程,不适合使用线程池以及父子线程
(父子线程值不会传递,线程池中的线程重复使用时候会存在这此线程业务处理使用到了上一次该线程业务处理的值)
InheritableThreadLocal
InheritableThreadLocal是ThreadLocal子类
该线程支持父子线程传递(子线程创建时,父线程线程副本会复制给子线程),也只适用于一次性线程(线程池中的线程重复使用时候会存在这此线程业务处理使用到了上一次该线程业务处理的值)
支持父子线程传递副本的核心代码
TransmittableThreadLocal
TransmittableThreadLocal 阿里组件, TransmittableThreadLocal是InheritableThreadLocal子类
支持父子线程传递,支持线程池以及每次都是拿最新父线程的值而不是像InheritableThreadLocal只创建线程对象的时候初始化一次(子线程业务处理时,会把父线程的Inheritable副本传递给子线程,同时也会copy下来用于当前线程的副本还原)
支持线程池的核心代码
主逻辑
把父线程的Inheritable副本传递给子线程,同时也会copy下来用于还原当前线程的副本
还原副本
三、如何避免内存泄漏的问题
- 产生内存泄漏的原因
由于Entry是WeakReference的子类,所以 作为引用对象的 ThreadLocal,就有可能会被Entry清除引用。如果这时候 ThreadLocal没有其他的引用,那么它肯定就会被GC回收了。
但是value 是强引用,而Entry 又被Entry[]持有,Entry[]又被ThreadLocalMap持有,ThreadLocalMap又被线程持有。只要线程不死或者 你不调用set,remove这两个方法之中任何一个,那么value指向的这个对象就始终 不会被回收。因为 不符合GC回收的两个条件的任何一个。
- 局部的ThreadLocal对象解决方案
可在业务执行完毕,在try{}finally()中finally语句块中的finally语句块中进行移除
- 全局的ThreadLocal对象解决方案
可继承ThreadPoolExecutor实现afterExecute方法进行移除(前提是通过该包装类来实现线程池,afterExecute该方法是线程任务执行完后需要执行的方法)
四、简单demo示例及结果展示
public class Test {
public static final TransmittableThreadLocal<String> globalThreadLocal = new TransmittableThreadLocal<>() {
@Override
protected String initialValue() {
return "";
}
};
public static void main(String[] args) throws Exception {
//这么初始化 remove() 后值就是initialValue设置的值,可以避免空指针问题
TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>() {
@Override
protected String initialValue() {
return "";
}
};
//两个全局连接池嵌套场景
ExecutorService executorService1 = new ThreadLocalAwareThreadPool(2, 2, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DefaultThreadFactory("executorService1"), new ThreadPoolExecutor.AbortPolicy());
//包装线程池
executorService1 = TtlExecutors.getTtlExecutorService(executorService1);
ExecutorService executorService2 = new ThreadLocalAwareThreadPool(1, 2, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DefaultThreadFactory("executorService2"), new ThreadPoolExecutor.AbortPolicy());
executorService2 = TtlExecutors.getTtlExecutorService(executorService2);
for (int i = 0; i < 4; i++) {
ExecutorService finalExecutorService = executorService2;
executorService1.execute(() -> {
try {
transmittableThreadLocal.set("parent" + Thread.currentThread().getId() + ":" + transmittableThreadLocal.get());
String s = transmittableThreadLocal.get();
finalExecutorService.execute(() -> {
try {
System.out.println(s);
transmittableThreadLocal.set("child" + Thread.currentThread().getId() + ":" + transmittableThreadLocal.get());
String ss = transmittableThreadLocal.get();
System.out.println(ss);
} finally {
transmittableThreadLocal.remove();
}
});
} finally {
transmittableThreadLocal.remove();
}
});
}
}
public static class ThreadLocalAwareThreadPool extends ThreadPoolExecutor {
public ThreadLocalAwareThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
//如果用submit需要自行get()获取异常,或者按afterExecute()备注来处理
super.afterExecute(r, t);
globalThreadLocal.remove();
}
}
}
结果如下图: