ThreadLocal的设计优点在哪👀

2,934 阅读3分钟
镇楼(疫情结束后的你.jpg)

前言

在家办公 💻,不敢出门 🚪,不敢理发 💇

没错,和大家一样,疫情结束后,我们就是镇楼图这个样子。

并且,你是不是也好几天没洗头了呢?

言归正传 ~

本篇文章来源于记忆中的一道题,实现一个 ThreadLocal

笔者第一次碰到这个题的时候,当时可是非常天真,分分钟写了一下,结果发现是个低配版,请你也继续往下看看,有没有和笔者一样天真过。

正文

低配 ThreadLocal 实现

在生活中的话,想知道一个东西优点在哪里,该怎么办?

干说,估计大多数人都听不懂。 但是,如果有同类产品作比较,那么优缺就显而易见了。那么同样的,下文中用笔者的低配版MyThreadLocal来看看ThreadLocal有什么优点。


其实当时看到这题的时候,还没仔细看过ThreadLocal的源码,但是脑中还是有几个关键字的,Map弱引用,于是动手就写了一个版本, 大体实现是这样的:

public class ThreadLocal<T> {

    private Map<Thread, T> threadValMap = Collections.synchronizedMap(new WeakHashMap<>());
    
    public void set(T value) {
        threadValMap.put(Thread.currentThread(), value);
    }

    public T get() {
        return threadValMap.get(Thread.currentThread());
    }

    // remove....
}

你别说,测试了一下,基本功能没毛病,Thread用完之后消除引用,通知 GC,过一会键值也成功被回收。

但是翻开 ThreadLocal 本身的源码,设计可是大相径庭。

这个低配版和正统版有什么区别?

对比两个ThreadLocal

上文提到的自己实现的ThreadLocal,下文我就一直称呼为MyThreadLocal吧。

MyThreadLocal的实现很简单,借助synchronizedMap方法实现了一个同步的弱引用HashMap。

那么ThreadLocal内部是怎样实现的,我也画了一张简图:

不同点之一 :效率

由于Thread类中设计时就带了一行ThreadLocal.ThreadLocalMap threadLocals = null; 作为属性。

所以,ThreadLocal在赋值的时候,只需要检查Thread类中的ThreadLocalMap是不是空的,空的就创建一个,不空就接着用。

上面两段文字描述的就是MyThreadLocalThreadLocal的第一处不同点:

低配版用synchronizedMap做为同步容器,synchronizedMap是同步容器,并不是并发优化容器,源码自然是大量的synchronized.

而ThreadLocal并没有同步操作,而是操作都是只针对自己当前线程进行操作,是天然的线程封闭。 用DB设计作为比喻的话,可以大致上类比为这个场景:

“单表加个字段就完事了,你非要再建个关联表,还得注意事务问题”

当然了,DB设计是有不同之处的, 这样性能就高下立判了,同样我们在单进程编码时也要注意,巧用不可变对象线程封闭,性能要优于同步

不同点之二:Map的Key类型

从上面的图片可以看到,MyThreadLocal的Map直接用Thread作为Key,而ThreadLocal 的Map用的是自己本身。

上文我也提到了,Thread直接作为弱引用的Key,GC也是成功回收了,那么区别在哪?

区别就是只有测试的时候,你才会new Thread();

实际中线程交由线程池管理,线程池内部采用线程复用,那么Thread将一直保持引用,不能被GC掉,可能导致内存泄露。

ThreadLocal倒是也有类似的问题,因为大多数情况我们都会使用static引用ThreadLocal,一直保持强引用。好在ThreadLocal提供了remove方法,只需开发者注意用完后调用即可。

最后

通过当时的笔者写出的低配版MyThreadLocal, 大概也知道了ThreadLocal优点在哪了,同时也感觉有个细节比较有趣:

ThreadLocalMap内部并没有使用HashMap做辅助,而且直接手写了一个HashMap

当时看到ThreadLocalMap的代码时,以为大佬们是想秀一下数据结构的功底,实际上,hashMap的诞生要晚于ThreadLocalMap,才是没有用的原因之一。

想想也是这样,Doug Lea和Josh Bloch这种级别的,还用秀基本功吗😄...