【Java】三种 ThreadLocal 的简单使用
三种 ThreadLocal 分别是:
- jdk 提供的
ThreadLocal - jdk 提供的
InheritableThreadLocal - 阿里巴巴提供的
TransmittableThreadLocal
文章中 demo 的环境代码👇
private ThreadLocal<Object> t = new ThreadLocal<>();
private ThreadLocal<Object> it = new InheritableThreadLocal<>();
private ThreadLocal tt = new TransmittableThreadLocal();
private void printForThreadLocal() {
System.out.println(Thread.currentThread().getName() + ":" + t.get());
}
private void printForInheritableThreadLocal() {
System.out.println(Thread.currentThread().getName() + ":" + it.get());
}
private void printForTransmittableThreadLocal() {
System.out.println(Thread.currentThread().getName() + ":" + tt.get());
}
/**
* @Description: 创建线程池
*/
private Executor createThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(10);
executor.setKeepAliveSeconds(60);
executor.setQueueCapacity(60);
executor.setThreadNamePrefix("myThreadPool: ");
executor.setTaskDecorator(new MyTaskDecorator());
executor.initialize();
return executor;
}
ThreadLocal
线程变量,仅供当前线程使用,不存在多线程分享变量问题
缺点:父子线程不可传递
三个方法:
void set(Object value)填充变量T get()获取变量void remove()删除变量【当线程结束后,线程变量也会被回收,显示的调用remove并不是必须的操作,但可以加快内存回收的速度】
最简单的 ThreadLocal 用法👇
证明线程之间不共享 ThreadLocal 中的值
@Test
public void test01ThreadLocal() {
t.set(1);
new Thread(() -> printForThreadLocal()).start();
printForThreadLocal();
}
InheritableThreadLocal
是 ThreadLocal 的子类,实现了父子线程共享变量问题
缺点:在使用线程池时,父子线程共享变量仍有问题
实现父子线程共享变量👇
@Test
public void test01InheritableThreadLocal() {
it.set(1);
new Thread(() -> printForInheritableThreadLocal()).start();
printForInheritableThreadLocal();
}
基本数据类型不可证明父子线程指向同一对象👇
@SneakyThrows
@Test
public void test02InheritableThreadLocal() {
it.set(1);
printForInheritableThreadLocal();
new Thread(() -> {
printForInheritableThreadLocal();
it.set(2);
printForInheritableThreadLocal();
}).start();
Thread.sleep(500);
printForInheritableThreadLocal();
}
InheritableThreadLocal中子父线程中指向同一对象👇
@SneakyThrows
@Test
public void test03InheritableThreadLocal() {
TestDTO testDTO = new TestDTO();
testDTO.setName("张三");
testDTO.setAge(20);
it.set(testDTO);
printForInheritableThreadLocal();
new Thread(() -> {
printForInheritableThreadLocal();
TestDTO pp = (TestDTO) it.get();
pp.setName("李四");
it.set(pp);
printForInheritableThreadLocal();
}).start();
Thread.sleep(500);
printForInheritableThreadLocal();
}
线程池在init新的线程时,会将主线程的InheritableThreadLocal传递给子线程👇
@SneakyThrows
@Test
public void test04InheritableThreadLocal() {
it.set(1);
printForInheritableThreadLocal();
Executor threadPool = createThreadPool();
threadPool.execute(() -> printForInheritableThreadLocal());
printForInheritableThreadLocal();
}
但如果在init子线程时,主线程InheritableThreadLocal中值为null,子线程也是null; 之后主线程被赋了新值,已经被init的子线程再次被调用时,主线程不会赋值给子线程(当前线程池大小为1,则可实现二次调用创建的子线程)👇
@SneakyThrows
@Test
public void test05InheritableThreadLocal() {
Executor threadPool = createThreadPool();
threadPool.execute(() -> printForInheritableThreadLocal());
it.set(1);
threadPool.execute(() -> printForInheritableThreadLocal());
printForInheritableThreadLocal();
}
TransmittableThreadLocal
解决了InheritableThreadLocal在线程池时父子线程传递的问题👇
@Test
public void test01TransmittableThreadLocal() {
Executor threadPool = TtlExecutors.getTtlExecutor(createThreadPool());
threadPool.execute(() -> printForTransmittableThreadLocal());
tt.set(1);
threadPool.execute(() -> printForTransmittableThreadLocal());
printForTransmittableThreadLocal();
}

浙公网安备 33010602011771号