线程数据共享必学的3个工具类:
ThreadLocal
InheritableThreadLocal
TransmittableThreadLocal
1.ThreadLocal:在当前线程中共享数据的,JUC 中提供的
2.InheritableThreadLocal:也是JUC中的一个工具类,解决 ThreadLocal 难以解决的问题
3.TransmittableThreadLocal:阿里开源的一个工具类,解决上面2个ThreadLocal 难以搞定的问题
也就是一个比一个强,也不能这么说,而是各有各的使用场景,
private ThreadLocal<String> userNameItl = new ThreadLocal<>();
// private InheritableThreadLocal<String> userNameItl = new InheritableThreadLocal<>();
public void inheritableThreadLocal1() throws InterruptedException {
userNameItl.set("张三");
log.info("userName:{}", userNameItl.get());
// 创建了一个子线程thread1,在子线程中区获取值
new Thread(() -> {
// ThreadLocal 时 userName:null
/**
* InheritableThreadLocal 时 userName:张三
*
* 存在的问题(子线程复制一次父线程之后,父子线程中的InheritableThreadLocal就没有关系了,父线程中|nheritableThreadLoca!的值再修改,也不会影响子线程中的值了)
* 见:https://www.bilibili.com/video/BV1Pz421S7Wx/?spm_id_from=pageDriver&vd_source=deac72a1d60ac5149e7eb3f9a4998402
* InheritableThreadLocal 如果用在线程池上,会有问题,可能导致严重的事故,这个一定要知道。
*
* 导致的原因:
* 分析下结果
* 从结果中看,线程池执行了2次任务,2次拿到的都是张三,和主线程第一次放入的值是一样的,而第二次主线程中放入的是李四啊,但是第二次线程池中拿到的却
* 是张三,这是什么原因?
* 上面线程池的大小是1,也就是说这个线程池中只有一个线程,所以让线程池执行的2次任务用到的都是一个线程,从上面的日志中可以看到线程名称都是 p001-1-
* thread-1,说明这两次任务,都是线程池中同一个线程执行的。
* 线程池中的线程是重复利用的,线程池中的po01-1-thread-1这个线程是什么时候创建的呢?谁创建的?他的父线程是谁?
* 1.是主线程中第一次调用executorSerice.execute让线程池执行任务的时候,线程池发现当前线程数小于核心线程数,所以会创建一个线程
* 2.他的父线程是谁?是创建他的线程,也就是执行第一次执行executorService.execute的线程,即主线程
* 子线程创建的时候,子线程会将父线程中lnheritableThreadLocal的值复制一份到子线程的InheritableThreadLocal中,从上面代码中可以看到,父线程
* nheritabiehreadLcal中第一次丢入的是张三,之后就调用线程池gexecute万法执行任务,比时,会在线程池中创建子线程,这个子线程会将分线程中
* InheritableThreadLocal中设置的张三,复制到子线程的lnhertableThreadLocal中,此时子线程中的用户名就是从父线程复制过来的,即:张三
* 复制之后,父子线程中的InheritableThreadLocal就没有关系了,父线程中|nheritableThreadLoca!的值再修改,也不会影响子线程中的值了,所以两次输出的都
* 是张三。
*
* 如何解决这个问题呢?
* 阿里的:TransmittableThreadLocal,这个就是为了解决这个问题来的。
* 1、需要引入maven配置
* <dependency>
* <groupId>com.alibaba</groupId>
* <artifactId>transmittable-thread-local</artifactId>
* <version>2.14.3</version>
* </dependency>
* 2、使用TransmittableThreadLocal 代替InherltableThreadLocal 或 ThreadLocal (TransmittapleThreadLocal<string> userNameTtl = new TransmittableThreadLocal<string>();)
* 程池需要用TtlExecutors.getTtlExecutorService 包裹一下,这个定不要漏掉
* Executorservice executorservice = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));
*
*/
log.info("userName:{}", userNameItl.get());
}, "thread1").start();
TimeUnit.SECONDS.sleep(1);
}
public static void main(String[] args) throws InterruptedException {
new CutterOperatorScheduleJob().inheritableThreadLocal1();
}