Handler 实现线程切换的核心在于消息的发送和处理分离:发送消息的线程与处理消息的线程可以不同,通过共享的 MessageQueue 和 Looper 机制实现跨线程通信。下面我将结合关键源码详细解析这一原理。

一、核心组件关系

Handler 机制主要由四个核心类组成:

  1. Handler:消息发送者和处理者
  2. Message:消息载体
  3. MessageQueue:消息队列,线程安全的数据结构
  4. Looper:消息循环器,驱动消息处理

二、线程切换实现原理

1. Looper 的线程绑定机制

每个线程要使用 Handler 必须先创建 Looper,通过 ThreadLocal 实现线程隔离:

java

// Looper.java
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 在 ActivityThread.main() 中初始化:

java

// ActivityThread.java
public static void main(String[] args) {
    Looper.prepareMainLooper(); // 创建主线程Looper
    Looper.loop(); // 启动消息循环
}

2. Handler 的创建与线程绑定

Handler 构造时会绑定当前线程的 Looper:

java

// Handler.java
public Handler(@Nullable Callback callback, boolean async) {
    mLooper = Looper.myLooper(); // 获取当前线程的Looper
    if (mLooper == null) {
        throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue; // 获取消息队列
}

3. 消息发送过程(跨线程)

当子线程通过 Handler 发送消息时:

java

// Handler.java
public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; // 设置处理该消息的Handler
    return queue.enqueueMessage(msg, uptimeMillis); // 入队
}

关键点:无论从哪个线程调用 sendMessage,最终都会将消息放入 Handler 绑定的 Looper 的消息队列中

4. 消息队列的线程安全

MessageQueue 通过 synchronized 保证线程安全:

java

// MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
    synchronized (this) { // 同步锁
        // 按时间顺序插入消息链表
        if (needWake) {
            nativeWake(mPtr); // 唤醒目标线程的Looper
        }
    }
    return true;
}

5. 消息处理过程(目标线程)

Looper 在目标线程中循环处理消息:

java

// Looper.java
public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;

    for (;;) {
        Message msg = queue.next(); // 可能阻塞
        if (msg == null) {
            return;
        }
        msg.target.dispatchMessage(msg); // 分发到Handler处理
        msg.recycleUnchecked();
    }
}

消息最终会回到发送时指定的 Handler 处理:

java

// Handler.java
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg); // 处理Runnable
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg); // 最终处理
    }
}

三、底层唤醒机制

当消息队列为空时,Looper 会通过 epoll 机制进入休眠状态:

java

// MessageQueue.java
Message next() {
    for (;;) {
        nativePollOnce(ptr, nextPollTimeoutMillis); // Native层阻塞
        // ...处理消息
    }
}

当有新消息插入队列时,会调用 nativeWake 唤醒:

java

void Looper::wake() {
    uint64_t inc = 1;
    write(mWakeEventFd, &inc, sizeof(uint64_t)); // 向eventfd写入数据
}

四、完整线程切换流程示例

  1. 主线程:创建 Handler 并绑定主线程 Looper
  2. 子线程:调用 handler.sendMessage(msg)
  3. 跨线程:消息被放入主线程的 MessageQueue
  4. 主线程:Looper.loop() 从队列取出消息并处理

java

// 主线程
Handler mainHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 在主线程处理消息
    }
};

// 子线程
new Thread(() -> {
    Message msg = mainHandler.obtainMessage();
    mainHandler.sendMessage(msg); // 发送到主线程
}).start();

五、关键设计要点

  1. 线程隔离:通过 ThreadLocal 确保每个线程有独立的 Looper
  2. 线程安全:MessageQueue 使用 synchronized 保证并发安全
  3. 高效唤醒:基于 Linux 的 epoll 机制实现精准唤醒
  4. 消息优先级:支持同步屏障和异步消息优先处理
  5. 内存管理:Message 对象池减少内存分配开销

这种设计使得 Android 能够高效安全地实现跨线程通信,同时保持较低的功耗


0 条评论

发表回复

您的电子邮箱地址不会被公开。