ThreadLocal
- 从 JDK1.2 版本开始提供了 ThreadLocal 类,以一种新的思路解决多线程并发问题。使用 ThreadLocal 实例维护多线程变量时,不会出现线程安全问题。虽然多个线程共用一个 ThreadLocal 实例,但在变量的使用上,各线程之间对变量不可见。
ThreadLocal 的使用
ThreadLocal threadLocal = new ThreadLocal();
-
ThreadLocal 提供无参的构造函数进行实例创建。在使用方面,该类也仅提供了几个简单的方法进行操作:
- set 方法:
threadLocal.set("threadLocal test")
对 ThreadLocal 进行值得设置。 - get 方法:
Object test = threadLocal.get()
进行值得获取。 - remove 方法:
threadLocal.remove();
删除对应线程中存储的值。
- set 方法:
-
在 JDK1.5 版本开始,ThreadLocal 提供泛型的支持,在获取值时不再需要需要进行类型强转。
ThreadLocal<String> threadLocal = new ThreadLocal();
threadLocal.set("threadLocal test");
String test = threadLocal.get();
源码浅析
- 通过构造函数我们发现,ThreadLocal 在构造函数中并没有做任何操作,所以我们从 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);
}
通过 set 方法我们可以看到,ThreadLocal 实际是在其内部维护了一个 ThreadLocalMap 实例进行变量的存储,并把该实例与线程进行绑定。在 ThreadLocalMap 中 key 的值为 this,也就是当前线程的 ThreadLocal 实例,value 为当前设置的值
-
在 get 方法中,通过调用
ThreadLocalMap map = getMap(t);
获取当前线程绑定的 ThreadLocalMap 实例,并获取 value 值。 -
值得注意的是 ThreadLocal 同一线程只能存储一个值,如果需要存储多个值,可以考虑封装成一个对象进行存储。
默认值
- ThreadLocal 通过
protected T initialValue()
方法进行 value 的初始化。
protected T initialValue() {
return null;
}
- 通过源码我们可以看到,该方法直接返回
null
。所以在创建实例后直接调用 get 方法时,我们得到的是空值。如果我们需要在 ThreadLocal 实例创建的时候进行初始化,可以通过继承 ThreadLocal 并重写initialValue()
方法即可。 - 那么
initialValue()
方法在何时进行调用的呢?通过查找源码我们在 get 方法中看到了该方法的调用。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
- 通过 get 方法执行流程可以看到,当 ThreadLocal 创建实例的时候,
ThreadLocalMap map = getMap(t);
返回的 map 值肯定为空,所以执行setInitialValue();
并返回,我们进入该方法:
private T setInitialValue() {
T value = initialValue(); //目标代码
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else createMap(t, value);
return value;
}
-
从 setInitialValue 方法实现可以看到,在该方法中调用了 initialValue 返回了我们自定义的返回值,并设置到 ThreadLocalMap 实例中。
-
通过上面的查看源码可以发现,ThreadLocal 在设置初始化值时,需要在第一次调用 get 方法时才会进行初始化,而不是在实例创建的时候进行初始化。
以上即为个人对 ThreadLocal 的简单理解。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于