简介

首先说一下这三者之间的区别:

  • 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层,都很顺利。

springboot es清除 springboot清理threadlocal_spring

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层无法取得父线程设置的值。

springboot es清除 springboot清理threadlocal_springboot es清除_02

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层可以正常取得父线程设置的值。

springboot es清除 springboot清理threadlocal_springboot es清除_03

第二章节请移步
Spring Boot使用ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal -2

其它注意

本文章样例:
工程名:spring-boot-inheritablethreadlocal
GitHub:https://github.com/zzyjb/SpringBootLearning

关于异步服务和线程池请移步

  1. Spring Boot 之异步Web服务