在Java中,ThreadLocal是实现线程安全的一种手段,它的作用是对于同一个ThreadLocal变量,在每一个线程中都有一个副本,当修改任何一个线程的变量时,不会影响到其他线程。它通过在每一个Thread中存储一个类似于map的结构,以ThreadLocal变量为key,变量值为value。
Dubbo在RPC调用的上下文中,需要借助ThreadLocal保存上下文。它从Netty中借鉴了InternalThreadLocal的实现,与Java官方的ThreadLocal不同的是,它内部没有采用哈希表的结构,而是采用了数组作为内部实现。下面就来看一下具体是如何实现的。
InternalThreadLocal模块主要有以下几个类:
使用方式
参见RpcContext类中,定义了
private static final InternalThreadLocal<RpcContext> LOCAL = new InternalThreadLocal<RpcContext>() {
@Override
protected RpcContext initialValue() {
return new RpcContext();
}
};
获取线程本地变量,只需调用
public static RpcContext getContext() {
return LOCAL.get();
}
重置
public static void restoreContext(RpcContext oldContext) {
LOCAL.set(oldContext);
}
移除
public static void removeContext() {
LOCAL.remove();
}
可以看出使用方式和官方的ThreadLocal是很类似的。
InternalThread
首先是InternalThread这个类,看它的类头和主要的field
/**
* InternalThread
*/
public class InternalThread extends Thread {
private InternalThreadLocalMap threadLocalMap;
以及获取和设置这个InternalThreadLocalMap变量的方法
/**
* Returns the internal data structure that keeps the threadLocal variables bound to this thread.
* Note that this method is for internal use only, and thus is subject to change at any time.
*/
public final InternalThreadLocalMap threadLocalMap() {
return threadLocalMap;
}
/**
* Sets the internal data structure that keeps the threadLocal variables bound to this thread.
* Note that this method is for internal use only, and thus is subject to change at any time.
*/
public final void setThreadLocalMap(InternalThreadLocalMap threadLocalMap) {
this.threadLocalMap = threadLocalMap;
}
从这个类可以看出,它跟官方的ThreaLocal的实现方式很像,也是通过一个内部的“map”来实现的。那么这个“InternalThreadLocalMap”真的是一个map吗?我们接着看。
remove
public static void remove() {
// 获取当前线程
Thread thread = Thread.currentThread();
// 若是InternalThread则设置为null,否则调用ThreadLocal的remove方法
if (thread instanceof InternalThread) {
((InternalThread) thread).setThreadLocalMap(null);
} else {
slowThreadLocalMap.remove();
}
}
destroy
public static void destroy() {
slowThreadLocalMap = null;
}
nextVariableIndex
public static int nextVariableIndex() {
// 先返回值再加1,通过Atomic变量让该操作为原子操作
int index = NEXT_INDEX.getAndIncrement();
// 溢出处理
if (index < 0) {
NEXT_INDEX.decrementAndGet();
throw new IllegalStateException("Too many thread-local indexed variables");
}
return index;
}</