java 中 ThreadLocal 的简单理解

本贴最后更新于 2490 天前,其中的信息可能已经渤澥桑田

ThreadLocal

  • 从 JDK1.2 版本开始提供了 ThreadLocal 类,以一种新的思路解决多线程并发问题。使用 ThreadLocal 实例维护多线程变量时,不会出现线程安全问题。虽然多个线程共用一个 ThreadLocal 实例,但在变量的使用上,各线程之间对变量不可见。

ThreadLocal 的使用

ThreadLocal threadLocal = new ThreadLocal();

  • ThreadLocal 提供无参的构造函数进行实例创建。在使用方面,该类也仅提供了几个简单的方法进行操作:

    1. set 方法:threadLocal.set("threadLocal test") 对 ThreadLocal 进行值得设置。
    2. get 方法:Object test = threadLocal.get() 进行值得获取。
    3. remove 方法:threadLocal.remove(); 删除对应线程中存储的值。
  • 在 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 的简单理解。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3186 引用 • 8212 回帖 • 1 关注
  • 线程
    122 引用 • 111 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...