ThreadLocal通过将变量绑定到线程上保证了数据隔离,从而保证了线程安全,使用场景大多 是维护一个线程的上下文对象。
ThreadLocal里存储的数据本质上就存储在Thread类下的一个Map里,也是线程类的成员变 量,和你的想法自定义线程类成员域其实差不多。
正确的使用姿势,就是用来定义线程级别的全局变量的。
全局变量是指,在任意类任意方法中都可以读取和设置;线程级意思就是“线程副本”,这 个变量在每个线程都可以有一个实例,但在线程内一定是唯一的。

Thread类中有一个成员变量threadLocals ,实际上,它就是一个hashtable (map)。也就
是存放所谓“线程副本”的地方。Java中说一下runnable和callable有什么区别

/*ThreadLocal values pertaining to this thread.This map is maintained
* by the ThreadLocal class.*/
ThreadLocal.ThreadLocalMap threadLocals = null;

而ThreadLocal实际就是操作这个hash table中固定一行记录的快捷方式而已。
我们换个low —点的代码来实现类似的功能

private Map<Object,Object> threadLocals = new HashMap<>();
public void setLocal(Object key,Object val) {
threadLocals.put(key,val);
}
public void getLocal(Object key) {
return threadLocals.get(key);
}
// ....省略n多thread的代码
我们再定义一组key,其实就是线程级全局变量名。显然,全局变量名需要在任意代码处都能 访问到,因此我们声明为public static的。
public class ThreadLocalKey {
/*请求id */
public static final String TRACE_ID = "traceld";
/*压测标*/
public static final String STRESS_FLAG = "stressFlag";
}

然后,我们就可以在任意类的任意代码处设置和读取这个“线程级全局变量” 了。
/*一处设置 traceld */
Thread.currentThread().setLocal (ThreadLocalKey.TRACE_ID,UUID.randomUUID().toString());
/另一处读取traceld,不在同一个类中调用/
Thread.currentThread().getLocal (ThreadLocalKey.TRACE_ID);
而JDK提供的ThreadLocal,实际充当的就是上面这个ThreadLocalKey.TRACE_ID这个hash table key的作用。JDK实现没有这么粗暴,它把Thread中的hash table给隐藏起来了,不 直接给外部访问。因此,使用ThreadLocal时,一般也是声明为static,或者能被静态访问 到。
那用ThreadLocal实现类似的全局存储traceId的功能,一般就是下面这样

private static final ThreadLocal<String> traceldLocal = new ThreadLocal<>();
public static String getTraceId() {
return threadldLocal.get();
public static String setTraceld(String traceId) {
threadldLocal.set(traceld);
}
}

然后在任意代码位置通过ThreadLocal来访问这个全局变量
/* —处设置 traceld */
RequestContext.setTraceld (UUID.randomUUID().toString());
/另一处读取traceld,不在同一个类中调用/
RequestContext.getTraceId() ;

Was this helpful?

0 / 0

发表回复 0

Your email address will not be published.