一、前言
场景1:均是单线程情况
直接使用ThreadLocal
及可以实现
场景2:存在异步情况
- 仅兼容 new
Thread
() - 兼容 new
Thread
() 和 线程池
问题分析
- 如果只使用原生的
ThreadLocal
,那么在异步的场景下ThreadLocal#get()
方法则获取不到,所以采用InheritableThreadLocal
代替ThreadLocal
InheritableThreadLocal
,则可以解决兼容 newThread
()场景InheritableThreadLocal
不能解决线程场景,因为线程池存在线程复用问题,不会每次new,所以线程取InheritableThreadLocal
的值还是残留第一次传递进来值,导致结果不正确
问题复现
private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i + "");
}
ThreadPoolTaskExecutor executor = build();
list.forEach(id -> {
contextHolder.set(id);
System.out.println(Thread.currentThread().getName() + "----" + contextHolder.get());
executor.execute(() -> System.out.println(Thread.currentThread().getName() + "----" + contextHolder.get()));
});
}
private static ThreadPoolTaskExecutor build() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程池大小
executor.setCorePoolSize(5);
// 最大可创建的线程数
executor.setMaxPoolSize(10);
// 队列最大长度
executor.setQueueCapacity(1000);
// 线程池维护线程所允许的空闲时间
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("taskExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
输出结果:
main----1
main----2
main----3
taskExecutor-1----1
main----4
taskExecutor-2----2
taskExecutor-3----3
main----5
taskExecutor-4----4
main----6
main----7
taskExecutor-1----1
taskExecutor-2----2
main----8
taskExecutor-5----5
taskExecutor-3----3
main----9
main----10
taskExecutor-4----4
taskExecutor-1----1
二、解决方案
1. maven依赖
...
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
2. 解决方案——源码
import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.TtlExecutors;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
public class TestDemo {
private static final ThreadLocal<String> contextHolder = new TransmittableThreadLocal();
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i + "");
}
Executor executor = build();
list.forEach(id -> {
contextHolder.set(id);
System.out.println(Thread.currentThread().getName() + "----" + contextHolder.get());
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName() + "----" + contextHolder.get());
};
executor.execute(runnable);
new Thread(runnable).start();
});
}
private static Executor build() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程池大小
executor.setCorePoolSize(5);
// 最大可创建的线程数
executor.setMaxPoolSize(10);
// 队列最大长度
executor.setQueueCapacity(1000);
// 线程池维护线程所允许的空闲时间
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("taskExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return TtlExecutors.getTtlExecutor(executor);
}
}
3. 输出结果
main----1
main----2
Thread-1----1
taskExecutor-1----1
main----3
Thread-2----2
taskExecutor-2----2
main----4
taskExecutor-3----3
Thread-3----3
main----5
taskExecutor-4----4
Thread-4----4
main----6
taskExecutor-5----5
Thread-5----5
taskExecutor-1----6
main----7
Thread-6----6
taskExecutor-2----7
main----8
Thread-7----7
taskExecutor-3----8
main----9
Thread-8----8
taskExecutor-4----9
main----10
Thread-9----9
taskExecutor-5----10
Thread-10----10