大家好,又见面了,我是你们的朋友全栈君。
以往遇到HandlerThread,对它的认识只是停留在Message<->Looper<->Handler上,知道它有自己的消息队列,仅此而已。随着编程的深入,表面上的理解无法满足要求,所以再次翻开HandlerThread源码,做梳理记录。
HandlerThread集成Thread,并重写了Thread类的run方法(如果我们自定义一个类继承HandlerThread,就用不到run函数了):
代码语言:javascript复制 @Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
从图中我们可以看到,HandlerThread的run方法先后执行了Looper.prepare()、Looper.loop(),因为我们知道这样做的目的是为了给HandlerThread实例建立一个属于它的消息队列(MessageQueue,这一点像极了Windows系统的窗口消息分发机制)。
代码语言:javascript复制 /** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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));
}
Looper.loop()的工作就是开始不断的从消息队列中取出消息(在loop函数里有个for循环,除非线程被系统杀死或者被调用quit函数,负责for循环会一直执行)
代码语言:javascript复制 /**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " msg.target " "
msg.callback ": " msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " msg.target " " msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
Long.toHexString(ident) " to 0x"
Long.toHexString(newIdent) " while dispatching to "
msg.target.getClass().getName() " "
msg.callback " what=" msg.what);
}
msg.recycleUnchecked();
}
}
有人说Looper中的sThreadLocal属性(ThreadLocal<Looper>类型)是个静态常量,怎么保证每个执行过Looper.prepare()、Looper.loop()的线程都有唯一的Looper呢?这个问题刚开始我也很好奇,后来发现原因在ThreadLocal类。
代码语言:javascript复制/**
* Implements a thread-local storage, that is, a variable for which each thread
* has its own value. All threads share the same {@code ThreadLocal} object,
* but each sees a different value when accessing it, and changes made by one
* thread do not affect the other threads. The implementation supports
* {@code null} values.
*
* @see java.lang.Thread
* @author Bob Lee
*/
public class ThreadLocal<T>
上述类的解释是说ThreadLocal实现了线程的本地存储,即所有的线程共同使用同一个ThreadLocal对象,但每个线程都会有一个ThreadLocal对象副本,每个线程的ThreadLocal对象副本又是相互独立的,互不影响。
推荐一篇介绍ThreadLocal的博文,写的很不错:彻底理解ThreadLocal
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157929.html原文链接:https://javaforall.cn