欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > 一文理解ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal

一文理解ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal

2025/9/17 17:11:42 来源:https://blog.csdn.net/m0_73363097/article/details/143819342  浏览:    关键词:一文理解ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal

介绍:

  1. ThreadLocal:在当前线程中共享数据的,JUC 中提供的
  2. InheritableThreadLocal:也是JUC中的一个工具类,解决 ThreadLocal 难以解决的问题
  3. TransmittableThreadLocal:阿里开源的一个工具类,解决上面2个ThreadLocal 难以搞定的问题

第一种情况:ThreadLocal 可以在当前线程中共享数据

用法

在当前线程中,调用 ThreadLocal.set()可以向当前线程中存入数据,然后在当前线程的其他位置可以调用 ThreadLocal.get() 获取当刚才放入的数据。

要点: ThreadLocal.set() 和 ThreadLocal.get() 需要再同一个线程中执行。

案例代码

  /***  ThreadLocal的简单存储使用--可以在当前线程中存储数据*/private final ThreadLocal<String> nameThreadLocal1 = new ThreadLocal<>();@Testpublic void threadLocalTest1(){//设置名字nameThreadLocal1.set("张三");//打印获取log.info("主线程中name:{}",nameThreadLocal1.get());//放在子线程中--设置名字为李四new Thread(()->{//继续设置名字nameThreadLocal1.set("李四");log.info("子线程1中name:{}",nameThreadLocal1.get());}).start();//放在子线程中-设置名字王五new Thread(()->{//继续设置名字nameThreadLocal1.set("王五");log.info("子线程2中name:{}",nameThreadLocal1.get());}).start();}

运行输出

16:00:06.258 [main] INFO com.study.tl.ThreadLocalTest - 主线程中name:张三
16:00:06.263 [Thread-1] INFO com.study.tl.ThreadLocalTest - 子线程1中name:李四
16:00:06.263 [Thread-2] INFO com.study.tl.ThreadLocalTest - 子线程2中name:王五
  1. 主线程(线程名称:main)中放入了张三,取出来也是张三
  2. 线程 thread1 中放入了李四,取出来也是李四
  3. 线程 thread2 中放入了王五,取出来也是王五

结论

通过ThreadLocal可以在当前线程中共享数据,通过其set方法在当前线程中设置值,然后在当前线程的其他任何位置,都可以通过ThreadLocal的get方法获取到这个值。

第二种情况:子线程是否可以获取ThreadLocal中的值呢?

代码

/*** 子线程获取不到主线程中ThreadLocal中的值*/private final ThreadLocal<String> nameThreadLocal2 = new ThreadLocal<>();@Testpublic void threadLocalTest2(){//设置名字nameThreadLocal2.set("张三");//打印获取log.info("主线程中name:{}",nameThreadLocal2.get());new Thread(()->{//直接拿主线程设置的值张三log.info("子线程中name:{}",nameThreadLocal2.get());}).start();}

执行输出

16:00:54.617 [main] INFO com.study.tl.ThreadLocalTest - 主线程中name:张三
16:00:54.621 [Thread-1] INFO com.study.tl.ThreadLocalTest - 子线程中name:null

子线程中没有拿到父线程中放进去的"张三",说明ThreadLocal只能在当前线程中共享数据。

结论

子线程无法获取父线程ThreadLocal中的set数据。

通过上面2个案例,可知ThreadLocal生效的条件是:其set和get方法必须在同一个线程才能共享数据。

那么有没有方法解决这个问题呢?(父线程中set数据,子线程中可以get到这个数据的)

JUC中的工具类 InheritableThreadLocal 可以解决这个问题。

第三种情况:InheritableThreadLocal(子线程可以获取父线程中存放的数据)

代码

     /*** 使用InheritableThreadLocal解决线程间数据传递问题*/private final ThreadLocal<String> nameThreadLocal3 = new InheritableThreadLocal<>();@Testpublic void threadLocalTest3(){//设置名字nameThreadLocal3.set("张三");//打印获取log.info("主线程中name:{}",nameThreadLocal3.get());new Thread(()->{//直接拿主线程设置的值张三log.info("子线程中name:{}",nameThreadLocal3.get());}).start();}

执行输出

16:03:24.828 [main] INFO com.study.tl.ThreadLocalTest - 主线程中name:张三
16:03:24.832 [Thread-1] INFO com.study.tl.ThreadLocalTest - 子线程中name:张三

结论

使用 InheritableThreadLocal ,子线程可以访问到父线程中通过InheritableThreadLocal.set进去的值。

第四种情况:InheritableThreadLocal:遇到线程池,可能出现问题?

代码

 /*** InheritableThreadLocal:遇到线程池 出现问题*/private final ThreadLocal<String> nameThreadLocal4 = new InheritableThreadLocal<>();@Testpublic void threadLocalTest4() throws InterruptedException {//为了看到效果,这里创建大小为1的线程池,注意这里为1才能方便看到效果ExecutorService executorService = Executors.newFixedThreadPool(1);nameThreadLocal4.set("张三");//打印获取log.info("主线程中name设置成张三:{}",nameThreadLocal4.get());executorService.execute(()->{log.info("主线程中name设置成张三,线程池中name值:{}",nameThreadLocal4.get());});//等待执行结束TimeUnit.SECONDS.sleep(1);//再次设置主线程中的值nameThreadLocal4.set("李四");//打印获取log.info("主线程中name设置成李四:{}",nameThreadLocal4.get());executorService.execute(()->{log.info("主线程中name设置成李四,线程池中name值:{}",nameThreadLocal4.get());});}

执行输出

16:08:22.578 [main] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成张三:张三
16:08:22.582 [pool-1-thread-1] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成张三,线程池中name值:张三
16:08:23.593 [main] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成李四:李四
16:08:23.594 [pool-1-thread-1] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成李四,线程池中name值:张三

存在的问题

InheritableThreadLocal 用在线程池上,会有问题,可能导致严重事故,这个一定要知道。

如何解决这个问题呢?

阿里的:TransmittableThreadLocal,这个就是为解决这个问题而来的。

第五种情况:TransmittableThreadLocal:解决线程池中不能够访问外部线程数据的问题

使用方法

需要引入maven配置

<dependency><groupId>com.alibaba</groupId><artifactId>transmittable-thread-local</artifactId><version>2.14.3</version></dependency>

使用 TransmittableThreadLocal 代替 InheritableThreadLocal 和 ThreadLocal

线程池需要用 TtlExecutors.getTtlExecutorService 包裹一下

ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));

示例代码

/*** InheritableThreadLocal:遇到线程池 出现问题使用TransmittableThreadLocal解决*/private final ThreadLocal<String> nameThreadLocal5 = new TransmittableThreadLocal<>();@Testpublic void threadLocalTest5() throws InterruptedException {//线程池需要用 TtlExecutors.getTtlExecutorService 包裹一下ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));nameThreadLocal5.set("张三");//打印获取log.info("主线程中name设置成张三:{}",nameThreadLocal5.get());executorService.execute(()->{log.info("主线程中name设置成张三,线程池中name值:{}",nameThreadLocal5.get());});//等待执行结束TimeUnit.SECONDS.sleep(1);//再次设置主线程中的值nameThreadLocal5.set("李四");//打印获取log.info("主线程中name设置成李四:{}",nameThreadLocal5.get());executorService.execute(()->{log.info("主线程中name设置成李四,线程池中name值:{}",nameThreadLocal5.get());});}

执行输出

16:27:00.716 [main] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成张三:张三
16:27:00.727 [pool-1-thread-1] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成张三,线程池中name值:张三
16:27:01.740 [main] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成李四:李四
16:27:01.741 [pool-1-thread-1] INFO com.study.tl.ThreadLocalTest - 主线程中name设置成李四,线程池中name值:李四

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词