在多线程编程中,有时会用到 ThreadLocal 类来处理一些变量。这个类的作用是为每个线程创建一个变量的副本,以达到变量线程安全的目的,所以这个类名叫 ThreadLocal,可以翻译为线程局部变量。
查看 ThreadLocal 的源码,会发现其中有个名为 ThreadLocalMap 的内部类,其实现原理类似 hashMap,那么我们很自然的会想到 ThreadLocalMap 应该是把每个线程 Thread 作为 key,而变量作为 value 存储起来的。
但是当看到 Threadlocal 中 set 方法的时候,估计大部分人会感到疑惑,为什么是这样的?set 方法源码如下:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
map.set(this, value),为什么是 this,而不是当前线程 t 呢?按照常规想法,map 以当前线程为 key,变量为 value 储存,取的时候也以当前线程为 key 取,不是刚好吗?
据说早期 JDK 确实是这么设计的,后来改成这样是因为性能原因。如果使用 Threadlocal 维护一个 ThreadLocalMap,为每个线程创建一个变量副本,那么当线程很多时,ThreadLocalMap 也会变得很大,经验告诉我们,一般用同一个数据结构存储大量数据的时候,效率都会变得很低,当然,事实也确实是这样。
后来的设计就是上面的代码了,查看 ThreadLocalMap map = getMap(t)中的 getMap()方法会发现,返回值是 Thread 里的一个 ThreadLocalMap 属性,也就是说,并不是由 ThreadLocal 去维护一个大的 ThreadLocalMap,而是由每个 Thread 自己去维护一个小的 ThreadLocalMap。为什么说是小的 ThreadLocalMap?因为 Thread 里的 ThreadLocalMap 是以 ThreadLocal 为键,变量为值,也就是说 map 里只有一个元素,通过把一个大 map 拆成若干个小 map 来提升效率,并且这个变量既然是线程局部变量,那么由 Thread 来维护,从关系上来看也很清晰。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于