简介
首先说一下这三者之间的区别:
- ThreadLocal:是JDK rt.jar包中的类,包为java.lang。它的作用是给线程提供一个本地变量,当线程消失的时候,所有的本地示例都会被回收。
- InheritableThreadLocal:同样是JDK rt.jar包中的类,包为java.lang。它是ThreadLocal的升级类,ThreadLocal在父子线程之间存在传递值的问题。在多线程和高并发流行的时代,ThreadLocal已经不能胜任线程的本地变量这个工作了。
- TransmittableThreadLocal:简称TTL,是阿里巴巴团队提供的一个框架。主要是解决InheritableThreadLocal在线程池情况,不能使用父线程中ThreadLocal中的值。
至于这三个类的源码分析,网上很多,我们这里暂时不说。下面给大家简单介绍下在WEB项目里面,这三个类的具体使用情况。
1. 同步情况下ThreadLocal的表现
1)首先引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2)建立Service层代码
先生成接口类
public interface PiceaService {
//测试ThreadLocal方法
String testThreadLocal() throws Exception;
}
然后完成实现
@Service
public class PiceaServiceImpl implements PiceaService {
@Override
public String testThreadLocal() throws Exception {
System.out.println("我是Service层处理线程,线程名:" + Thread.currentThread().getName());
System.out.println(" ThreadLocalUtil保存的值为:" + ThreadLocalUtil.getValue());
ThreadLocalUtil.remove();
return "sss";
}
}
3)建立Controller层代码
@RestController
public class PiceaContoller {
@Autowired
private PiceaService piceaService;
@RequestMapping("/testTl")
public String testThreadLocal() throws Exception {
System.out.println("我是Controller层处理线程,线程名:" + Thread.currentThread().getName());
ThreadLocalUtil.setValue("我是:testThreadLocal");
System.out.println("这里是处理过程,处理中.........");
System.out.println(" ThreadLocalUtil保存的值为:" + ThreadLocalUtil.getValue());
String ret = piceaService.testThreadLocal();
return "testThreadLocal:" + ret;
}
}
4)测试结果
浏览器中输入http://localhost:2001/testTl
从图片中可以看出,设置的值无论是在Controller层,还是Service层,都很顺利。

2. 异步情况下ThreadLocal的表现
同步的情况下,ThreadLocal表现还可以,在各个层之间使用都很正常,下面我们改成异步的看看效果。
1)增加异步配置
在启动类中,增加开启异步支持,增加注解"@EnableAsync"。
@EnableAsync
@SpringBootApplication
public class SpringBootInheritablethreadlocalApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootInheritablethreadlocalApplication.class, args);
}
}
2)在Service层增加方法
先增加接口
void testThreadLocalAsync() throws Exception;
然后增加实现
@Async
@Override
public void testThreadLocalAsync() throws Exception {
System.out.println("我是Service层处理线程,线程名:" + Thread.currentThread().getName());
System.out.println(" ThreadLocalUtil保存的值为:" + ThreadLocalUtil.getValue());
ThreadLocalUtil.remove();
}
3)在Controller层增加测试方法
@RequestMapping("/testTlA")
public String testThreadLocalAsync() throws Exception {
System.out.println("我是Controller层处理线程,线程名:" + Thread.currentThread().getName());
ThreadLocalUtil.setValue("我是:testThreadLocalAsync");
System.out.println("这里是处理过程,处理中.........");
System.out.println(" ThreadLocalUtil保存的值为:" + ThreadLocalUtil.getValue());
piceaService.testThreadLocalAsync();
return "testThreadLocalAsync:";
}
4)测试结果
浏览器中输入http://localhost:2001/testTlA
在结果中,可以发现Service层无法取得父线程设置的值。

3. 异步情况下InheritableThreadLocal的表现
在异步的情况下,ThreadLocal已经取不到父线程的值,现在我们是要它的升级类InheritableThreadLocal看看效果。
1)在Service层增加方法
先增加接口
void testThreadLocalAsyncItl() throws Exception;
然后增加实现
@Async
@Override
public void testThreadLocalAsyncItl() throws Exception {
System.out.println("我是Service层处理线程,线程名:" + Thread.currentThread().getName());
System.out.println(" InheritableThreadLocalUtil保存的值为:" + InheritableThreadLocalUtil.getValue());
InheritableThreadLocalUtil.remove();
}
3)在Controller层增加测试方法
@RequestMapping("/testItl")
public String testInheritableThreadLocal() throws Exception {
System.out.println("我是Controller层处理线程,线程名:" + Thread.currentThread().getName());
InheritableThreadLocalUtil.setValue("我是:testInheritableThreadLocal");
System.out.println("这里是处理过程,处理中.........");
System.out.println(" InheritableThreadLocalUtil保存的值为:" + InheritableThreadLocalUtil.getValue());
piceaService.testThreadLocalAsyncItl();
return "testInheritableThreadLocal:";
}
4)测试结果
浏览器中输入http://localhost:2001/testItlTl
在结果中,可以看到Service层可以正常取得父线程设置的值。

第二章节请移步
Spring Boot使用ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal -2
其它注意
本文章样例:
工程名:spring-boot-inheritablethreadlocal
GitHub:https://github.com/zzyjb/SpringBootLearning
关于异步服务和线程池请移步
网友评论