前面文章多线程间的同步控制和通信,是为了保证多个线程对共享数据争用时的正确性的。那如果一个操作本身不涉及对共享数据的使用,相反,只是希望变量只能由创建它的线程使用(即线程隔离)就需要到线程本地存储了。
Java 通过 ThreadLocal
提供了程序对线程本地存储的使用。
通过创建 ThreadLocal
类的实例,让我们能够创建只能由同一线程读取和写入的变量。因此,即使两个线程正在执行相同的代码,并且代码引用了相同名称的 ThreadLocal
变量,这两个线程也无法看到彼此的存储在 ThreadLocal
里的值。否则也就不能叫线程本地存储了。
本文大纲如下:
ThreadLocal
ThreadLocal
是 Java 内置的类,全称 java.lang.ThreadLoal
, java.lang
包里定义的类和接口在程序里都是可以直接使用,不需要导入的。
ThreadLocal
的类定义如下:
public class ThreadLocal<T> {
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//......
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
}
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null) {
m.remove(this);
}
}
protected T initialValue() {
return null;
}
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
return new SuppliedThreadLocal<>(supplier);
}
// ...
}
上面只是列出了 ThreadLocal
类里我们经常会用到的方法,这几个方法他们的说明如下。
T get()
- 用于获取ThreadLocal
在当前线程中保存的变量副本。void set(T value)
- 用于向ThreadLocal
中设置当前线程中变量的副本。void remove()
- 用于删除当前线程保存在ThreadLocal
中的变量副本。initialValue()
- 为ThreadLocal
设置默认的get
方法获取到的始值,默认是 null ,想修改的话需要用子类重写 initialValue 方法,或者是用TheadLocal
提供的withInitial
方法 。
下面我们详细看一下 ThreadLocal
的使用。
创建和读写 ThreadLocal
通过上面 ThreadLocal
类的定义我们能看出来, ThreadLocal
是支持泛型的,所以在创建 ThreadLocal
时没有什么特殊需求的情况下,我们都会为其提供类型参数,这样在读取使用 ThreadLocal
变量时就能免去类型转换的操作。
private ThreadLocal threadLocal = new ThreadLocal();
threadLocal.set("A thread local val