引言: 线程是一段可执行的代码,当可执行代码执行完成后,线程生命周期便该终止了,线程也即退出了。
带着两个问题思考:
1、代码执行完了线程生命周期便终止,那为什么主线程能一直执行而不退出呢?
2、Android 是如何实现线程同步的?
此过程涉及到几个类,先做普及 ActivityThread: ActivityThread.main() 函数作为程序入口。
Looper: Looper.loop() 死循环,用于保证该线程生命周期一直执行,不会退出。
ThreadLocal: 存放 Looper,可实现线程共享。
MessageQueue: 存放有序的 Message,管理任务
Message: 消息
Handler: 发送消息,处理任务(handleMessage() 方法)
public class ThreadLocal<T> {
...
public T get() {
//以当前线程为 key 获取 value,实现线程共享
Thread t = Thread.currentThread();
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();
}
}
从主线程开始执行到 Handler 处理任务分析:
应用的入口从 ActivityThread.main() 开始执行。当前运行的线程即为主线程(mainThread)。
public final class ActivityThread extends ClientTransactionHandler {
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
}
1 > 在 main() 中调用 Looper.prepareMainLooper() 时实际是通过 Looper.prepare(false) 创建 Looper ,并将 looper 保存在 ThreadLocal 中。存放在 ThreadLocal 中的好处是可以线程共享,即只要在当前线程中就可以获取到 Looper 对象。
2 > Looper 对象初始化时生成 MessageQueue 对象,MessageQueue 是一个单向链表,用来存放 message 并指向下一个 messgae,这种结构保证了消息顺序执行。
public final class Looper {
//单例,存放各个线程中 Looper 对象
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
...
//消息队列,用来存放 message
final MessageQueue mQueue;
final Thread mThread;
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建 Looper 并存放在 sThreadLocal 中
sThreadLocal.set(new Looper(quitAllowed));
}
//获取 当前 Looper 对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
}
public final class MessageQueue {
Message mMessages;
}
3 > Looper.loop() 通过死限循环 调用 queue.next() 方法获取 message 信息。
public final class Message implements Parcelable {
//指向下一个消息
Message next;
//发送消息的 Handler ,用于处理任务
Handler target;
}
public final class Looper {
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;
...
//死循环调用 queue.next() 获取 message
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
...
try {
//如果有 msg 不为空,调用 target 即 handler 的 dispatchMessage()
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
}
...
msg.recycleUnchecked();
}
}
}
public class Handler {
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
...
} else {
...
//即各 Handler 处理任务的逻辑
handleMessage(msg);
}
}
}
public final class MessageQueue {
Message next() {
...
for (;;) {
...
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
...
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
...
}
}
...
}
}
}
从 Handler 发送消息分析:
Handler 初始化时会通过 Looper.myLooper() 获取当前线程的 Looper 对象,并获取到 Looper 中的 MessageQueue 对象。由此可以猜测 当 handler.sendMessage(Message msg) 时发送的消息会被存放在 MessageQueue 中,与上面分析 MessageQueue.next 获取消息对应。
public class Handler {
//通过 Looper.myLooper() 获取创建该对象时
final Looper mLooper;
//用于存放 message
final MessageQueue mQueue;
public Handler(Callback callback, boolean async) {
//创建 Handler 时,Handler 会获取到当前线程的 Looper 对象,并获取到 MessageQueue
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
}
发送消息 sendMessage()
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
...
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//即 Looper 中的 MessageQueue
MessageQueue queue = mQueue;
...
return enqueueMessage(queue, msg, uptimeMillis);
}
下一步 msg.target = this 很重要
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//将当前 handler 对象赋值给 message.target,此操作是为了绑定 handler ,用于处理消息时分发给当前 Handler
msg.target = this;
...
return queue.enqueueMessage(msg, uptimeMillis);
}
以上是 handler.sendMessage 发送消息时将 message 发送给 messageQueue 对象,并将自身赋值给 message.target 与 message 绑定,绑定是为了在处理 message 时便于分辨执行特定的 handler.handleMessage() 方法。
再看 MessageQueue 中 enqueueMessage(msg, uptimeMillis) 方法
boolean enqueueMessage(Message msg, long when) {
...
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
...
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
...
}
msg.next = p;
prev.next = msg;
}
...
}
return true;
}
enqueueMessage 只是通过 when 即 delayMillis 延迟处理的时间长短给插入的 message 排序。
以上分别分析了 处理任务与发送消息的 流程,流程如下:
ActivityThread.main() --> Looper.prepareMainLooper() --> Looper.loop() --> queue.next() --> msg.target.dispatchMessage() --> handler. dispatchMessage() --> handler. handleMessage()
回到开始提出的两个问题,通过分析可以得出以下结论:
问:1、为什么主线程能一直执行而不退出?
答: Looper.loop() 中通过死循环让程序一直执行,不会退出。并会持续调用 MessageQueue.next() 方法获取 message。
问:2、Android 是如何实现线程同步的?
答: 不同线程中发送的消息都是发送到 创建 Handler 时所在的线程的 MessageQueue 对象中,通过 ThreadLocal 会获取该线程中的 Looper 和 MessageQueue。当消息插入至 MessageQueue 中时, MessageQueue.next() 会获取到 message ,之后会调用 message.target.dispatchMessage(),最后调用 handleMessage() 处理任务。
此过程中涉及到 IdleHandler 、和 线程挂起 nativePollOnce() 将另作篇幅分析