1.ThreadLocal 概念
ThrealLocal 提供线程据局部变量。通过 get 和 set 方法的方法的访问都是线程私有的,独立初始化的变量副本。
通俗来讲:它可以以线程为界限来存储数据,该数据存储后,只有在指定的线程中才能获取到存储的数据,对于其它线程而言该变量为默认初始值(null)。
使用场景:当某些数据以线程为作用域,并且不同的线程数据互相独立的时候,就可以考虑使用 ThreaLocal
2.关键类及方法
ThreadLocal 是一个泛型类,
ThreadLocal#get()
public T get() {
//1.获取当前线程
Thread t = Thread.currentThread();
//2.传入线程获取 ThreadLocalMap 对象。
ThreadLocalMap map = getMap(t);
if (map != null) {
//3.如果不为null,传入 ThreadLcoal 获取到ThreadLocalMap.Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//4.为 null 进行初始化
return setInitialValue();
}
// 2.1ThreadLocal#getMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//2.2 Thread#threadLocals,线程本地数组存储,由ThreadLocal维护
ThreadLocal.ThreadLocalMap threadLocals = null;
//4.1 初始化ThreadLocaMap。
private T setInitialValue() {
//初始化为 value = null
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//创建 ThreadLocalMap
createMap(t, value);
return value;
}
//4.2 key 为当前线程的,value 初始为 null
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
首先获取当前线程的 ThreadLocalMap 变量,如果为 nll,就调用 setInitialValue() 方法进行初始化,默认情况下,initialValue() 的值返回都null,可以重写这个方法设置我们想要的初始值。
可以看到,所有的操作最终都是和当前线程的 ThreadLocalMap 变量打交道。
ThreadLocal#set()
public void set(T value) {
Thread t = Thread.currentThread();
//获取 ThreadLocalMap 用于存储变量值, key 为 ThreadLocal<>
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//否则创建 ThreadLocalMap
createMap(t, value);
}
在 set() 方法中,先获取到当前线程,然后通过 getMap(Thread t) 方法获取一个 ThreadLocalMap,如果这个 map 不为空的话,就将 ThrealLocal 和 value 设置进去,不然的话就创建一个 ThrealLocalMap 然后再进行设置。
ThreadLocal#ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的一个静态内部类,每一个 Thread 都有一个对应的 ThreadLocalMap。通过 ThreadLocalMap 来存储 ThreadLocal 对象。
//Thread#threadLocals,线程本地数组存储,由ThreadLocal维护
ThreadLocal.ThreadLocalMap threadLocals = null;
//ThreadLocalMap
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private static final int INITIAL_CAPACITY = 16;
//ThreadLocal 存储在 table 数组中。以弱引用的方式的键值对
private Entry[] table; }
ThreadLocal 中的 set 和 get 方法,都是操作 ThreadLocal#ThreadLocalMap 中的
private Entry[] table 来保存 ThreadLocal 中的值。
3.示例代码
public class ThreadLocalActivity extends AppCompatActivity {
private static final String TAG = ThreadLocalActivity.class.getSimpleName();
private ThreadLocal<String> mMainLocal = new ThreadLocal<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_local);
mMainLocal.set("第一次赋值");
Log.i(TAG, "onCreate: mMainLocal = " + mMainLocal.get());
new Thread("Thread-1") {
@Override
public void run() {
Log.i(TAG, "Thread-1 get : " + mMainLocal.get());
mMainLocal.set("第二次赋值:");
Log.i(TAG, "Thread-1 get : " + mMainLocal.get());
}
}.start();
}
}
2021-10-18 10:43:23.470 24428-24428/com.tsp.learn I/ThreadLocalActivity: onCreate: mMainLocal = 第一次赋值
2021-10-18 10:43:23.470 24428-24628/com.tsp.learn I/ThreadLocalActivity: Thread-1 get : null
2021-10-18 10:43:23.471 24428-24628/com.tsp.learn I/ThreadLocalActivity: Thread-1 get : 第二次赋值: