微服务之间共享threadlocal_threadlocal跨线程传递解决方案(上)

1.在面试的过程中。经常会遇到面试官提到threadlocal的问题,很多情况下:

面试官最爱问的是:

threadlocal是做什么用的,用在哪些场景当中?

这个很多同学基本上也能提到:

ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。简单易懂的就是。每个线程有自己的数据副本,当线程结束后可以独立回收。

通常使用场景:

比如spring mvc收到请求。拦截器将用户id等数据放到threadlocal当中。在当前线程就可以直接拿到数据

具体例子:

有些同学会说出开源项目中有些地方会用到:

比如这种,比如mysql读写分离。主写读从过程中,类似于shardingsphere的中间件。就通过threadlocal来实现某一次读请求路由到主库。通过threadlocal设置标识即可

2.那么面试官继续问:

如果我启动另外一个线程。那么在主线程设置的threadlocal值能被子线程拿到吗?

如果拿不到,怎么去解决这个问题。有的同学一定会想这种场景比较少。顶多就是面试官找茬罢了

其实不然。这种场景非常普遍。举一个例子:

现在微服务基本上属于各个大厂小厂的标配。有一个问题。全链路如何来做监控。如果用过spring cloud的同学一定会说。zipkin,有的可能也会说cat,pinpoint,skywalking等等,

暂且不讨论这些全链路组件的优劣。在全链路组件落地的过程中,threadlocal是一个相当关键的步骤。拿zipkin的实现来说:

核心的数据传递都通过threadlocal来实现

那么回到我刚才的问题。threadlocal跨线程是否能够传递呢?那么我们做一个实验:

相关代码。我们在父线程设置了一个threadlocal。另外启动一个线程去获取

运行结果:

结论:拿不到数据。获取的是个null

那我们应该怎么去解决这个问题:

在java8中提供了一个这个类(InheritableThreadLocal):

从字面意思来看:可以实现父线程到子线程的共享,那么我们实验一下

将实现换成了InheritableThreadLocal

看一下效果 (果然解决了问题):

InheritableThreadLocal原理:

看一下目录结构:

复写了父类3个方法

当主线程中对该变量进行set操作的时候,和ThreadLocal一样会初始化一个ThreadLocalMap对实际的变量值进行存储,以ThreadLocal为key,值为value,如果有多个ThreadLocal变量也都是存储在这个Map中。该Map使用的是HashMap的原理进行数据的存储,但是和ThreadLocal有一点差别,因为其覆写了createMap的方法。

在Thread类当中,可以看出Thread类维护了两个成员变量,ThreadLocal以及InheritableThreadLocal,数据类型都是ThreadLocalMap.这也就解释了为什么这个变量是线程私有的。但是如果要知道为什么父子线程的变量传递,那就继续看一下源码。当我们在主线程中开一个新的子线程的时候,开始会new一个新的Thread

在thread构造函数中,new一个thread方法

可以看到,最后会调用ThreadLocal的createInheritedMap方法,而该方法会新建一个ThreadLocalMap,看一下构造函数的内容:

parentMap就是父线程的ThreadLocalMap,这个构造函数的意思大概就是将父线程的ThreadLocalMap复制到自己的ThreadLocalMap里面来,这样我们就可以使用InheritableThreadLocal访问到父线程中的变量了

但是这个就能解决问题了吗。并不是~

下个小结我会继续讲解InheritableThreadLocal在多线程调用过程中还存在哪些坑。如何解决

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,ThreadLocal是一种线程局部变量,它可以在多个线程中存储和访问数据,每个线程都有自己独立的副本。然而,ThreadLocal的数据在子线程中默认是无法传递的。但是,可以通过一些特殊的ThreadLocal实现类来实现ThreadLocal数据在子线程中的传递。 一种实现方式是使用InheritableThreadLocal类。InheritableThreadLocalThreadLocal的一个子类,它允许子线程继承父线程ThreadLocal变量。当一个线程创建子线程时,子线程会自动拥有父线程的InheritableThreadLocal变量的副本。这样,父线程中设置的ThreadLocal变量的值可以在子线程中访问到。 另一种实现方式是使用TransmittableThreadLocal类。TransmittableThreadLocal是一个第三方库,它提供了更强大的功能,可以在线程传递ThreadLocal变量的值。它通过在线程切换时保存和恢复ThreadLocal变量的值来实现传递。使用TransmittableThreadLocal,可以在父线程中设置ThreadLocal变量的值,并在子线程中访问到这个值。 下面是使用InheritableThreadLocal和TransmittableThreadLocal传递ThreadLocal变量到子线程的示例代码: ```java // 使用InheritableThreadLocal传递ThreadLocal变量到子线程 ThreadLocal<String> threadLocal = new InheritableThreadLocal<>(); threadLocal.set("Hello, World!"); Thread thread = new Thread(() -> { String value = threadLocal.get(); System.out.println("Value in child thread: " + value); }); thread.start(); // 使用TransmittableThreadLocal传递ThreadLocal变量到子线程 ThreadLocal<String> threadLocal = new TransmittableThreadLocal<>(); threadLocal.set("Hello, World!"); Thread thread = new Thread(() -> { String value = threadLocal.get(); System.out.println("Value in child thread: " + value); }); thread.start(); ``` 在上面的代码中,我们首先创建了一个ThreadLocal变量,并在父线程中设置了它的值。然后,我们创建了一个子线程,并在子线程中获取并打印了ThreadLocal变量的值。使用InheritableThreadLocal或TransmittableThreadLocal,我们可以在子线程中成功访问到父线程设置的ThreadLocal变量的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值