一切从Android的Handler讲起(三):Looper的唯一性——ThreadLocal
1、Looper 在线程上具备唯一性,其原因在于 ThreadLocal;2、MessageQueue 也具备线程上的唯一性,其原因在于 Looper 构造时创建了对应的 MessageQueue;3、Looper.prepare() 方法只能调用一次- - - - - Looper 的唯一性篇完 - - - - -
本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net
一切从 Android 的 Handler 讲起(三):Looper 的唯一性——ThreadLocal
肥柴在起始篇:一切从 Android 的 Handler 讲起(一):Handler 工作机制中提及到,一个 Looper 对应一个线程,也就是说,Looper 在线程上具备唯一性。
那么问题来了,Handler 底层是如何来实现 Looper 的唯一性的呢?
肥柴决定从 Looper 的源码入手,我们知道一个线程的 Looper 的创建是调用 Looper 的 prepare 方法,那我们就从这里开始下手。
/** Looper.class */
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
可以很清楚的看到,prepare 方法中,通过一个 ThreadLocal 来保证了 Looper 在线程上的唯一性。
我们再来看看 Looper 的构造函数,可以发现,Looper 构造函数内创建了对应的 MessageQueue,也就是我们常说的,一个线程只有一个 Looper,MessageQueue 在 Looper 对应的线程内。
/** Looper.class */
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
ThreadLocal 是提供了在与当前线程绑定的局部变量,不同线程都会取到不同的值的工具类,这在一些并发、变量传递等场景下非常好用。肥柴继续发出疑问:那 ThreadLocal 内部又是通过什么样的原理来做到不同线程取不同的值的呢?
我们从 ThreadLocal 的 get 和 set 源码入手来了解其原理。
/** ThreadLocal.class */
public T get() {
Thread t = Thread.currentThread();
/** 注释1 */
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();
}
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;
}
ThreadLocalMap getMap(Thread t) {
/** 注释2 */
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
/** 注释3 */
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
无论是 ThreadLocal 的 get 方法还是 set 方法,其原理思路就是:
1、获取当前 Thread;
2、获取当前 Thread 对应的 ThreadLocalMap(注释 1),包括了设置(注释 2)、先创建后设置(注释 3)两种;
3、以 ThreadLocal 为 Key,需要保存的 value 为 ThreadLocalMap 的 value,保存到对应的 ThreadLocalMap(一个非常类似于 HashMap 的结构)中或者从其中取出;
基于以上肥柴可以得知 ThreadLocal 的大致工作原理:每个线程都有一个 ThreadLocalMap 结构,其中就保存着当前线程所持有的所有 ThreadLocal。ThreadLocal 本身只是一个引用,没有直接保存值,值是保存在 ThreadLocalMap 中,ThreadLocal 作为 key,值作为 value。可以用下面的图来概括。
肥柴总结
1、Looper 在线程上具备唯一性,其原因在于 ThreadLocal;
2、MessageQueue 也具备线程上的唯一性,其原因在于 Looper 构造时创建了对应的 MessageQueue;
3、Looper.prepare() 方法只能调用一次
- - - - - Looper 的唯一性篇完 - - - - -
更多推荐
所有评论(0)