深入理解 ThreadLocal
前言
上篇文章 深入理解 Handler 消息机制 中提到了获取线程的 Looper 是通过 ThreadLocal
来实现的:
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
每个线程都有自己的 Looper,它们之间不应该有任何交集,互不干扰,我们把这种变量称为 线程局部变量 。而 ThreadLocal
的作用正是存储线程局部变量,每个线程中存储的都是独立存在的数据副本。如果你还是不太理解,看一下下面这个简单的例子:
public static void main(String[] args) throws InterruptedException { ThreadLocal<Boolean> threadLocal = new ThreadLocal<Boolean>(); threadLocal.set(true); Thread t1 = new Thread(() -> { threadLocal.set(false); System.out.println(threadLocal.get()); }); Thread t2 = new Thread(() -> { System.out.println(threadLocal.get()); }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(threadLocal.get()); }
执行结果是:
false null true
可以看到,我们在不同的线程中调用同一个 ThreadLocal 的 get() 方法,获得的值是不同的,看起来就像 ThreadLocal 为每个线程分别存储了不同的值。那么这到底是如何实现的呢?一起来看看源码吧。
以下源码基于 JDK 1.8 , 相关文件:
ThreadLocal
首先 ThreadLocal 是一个泛型类,public class ThreadLocal<T>
,支持存储各种数据类型。它对外暴露的方法很少,基本就 get()
、set()
、remove()
这三个。下面依次来看一下。
set()
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); // 获取当前线程的 ThreadLocalMap if (map != null) map.set(this, value); else createMap(t, value); // 创建 ThreadLocalMap }
这里出现了一个新东西 ThreadLocalMap
,暂且就把他当做一个普通的 Map。从 map.set(this, value)
可以看出来这个 map 的键是 ThreadLocal
对象,值是要存储的 value
对象。其实看到这,ThreadLocal 的原理你应该基本都明白了。