Handler到底是怎么实现子线程的Message到主线程下被处理的?
Posted zhangjin1120
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler到底是怎么实现子线程的Message到主线程下被处理的?相关的知识,希望对你有一定的参考价值。
Handler机制的作用真的是线程间通信吗?
Handler到底是怎么实现子线程的Message到主线程下被处理的?
郭霖大神的文章:Android异步消息处理机制完全解析,带你从源码的角度彻底理解,详细分析了从sendMessage()到handleMessage()的过程。
handler.sendMessage(msg);
是在子线程的run()方法中执行的,也就是说当前的代码执行环境是子线程,而handleMessage()
方法是运行在主线程的,那么,具体是怎么实现的?
反复看郭霖大神的文章,可以梳理出一个逻辑:
- 在子线程中,产生msg,并获取主线程的Handler,发送msg。
new Thread(new Runnable()
@Override
public void run()
Message message = new Message();
message.arg1 = 1;
handler.sendMessage(message);
).start();
- msg最终进入MessageQueue。
final boolean enqueueMessage(Message msg, long when)
...
//单链表的插入
Message p = mMessages;
msg.next = p;
mMessages = msg;
...
return true;
- 主线程一直在轮询MessageQueue,取出刚入队的msg。msg持有handler的引用target,直接msg.target.dispatchMessage()。
public static final void loop()
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true)
Message msg = queue.next(); // might block
if (msg != null)
if (msg.target == null)
return;
...
msg.target.dispatchMessage(msg);
msg.recycle();
- dispatchMessage()内部调用handleMessage()。
public void dispatchMessage(Message msg)
...
handleMessage(msg);
还是有两个问题没有弄明白:子线程是什么时候结束的?代码从哪里开始进入主线程的运行环境的?为了彻底搞清楚这个问题,只能手写一个handler机制:
Handler.java
public class Handler
private MessageQueue mQueue;
final Looper mLooper;
public Handler()
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;
public void handleMessage(Message msg)
public void dispatchMessage(Message msg)
handleMessage(msg);
public void sendMessage(Message msg)
MessageQueue queue = mQueue;
if (queue != null)
enqueueMessage(queue, msg);
private void enqueueMessage(MessageQueue mQueue, Message msg)
msg.target = this;
mQueue.enqueueMessage(msg);
Looper.java
public class Looper
static MessageQueue mQueue;
private static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private Looper()
mQueue = new MessageQueue();
public static void prepare()
if (sThreadLocal.get() != null)
throw new RuntimeException("Only one Looper may be created per thread");
sThreadLocal.set(new Looper());
public static Looper myLooper()
return sThreadLocal.get();
public static void loop()
System.out.println(Thread.currentThread().getName() + ":进入loop()");
Looper looper = myLooper();
for(;;)
Message msg = looper.mQueue.next();
if(msg == null)
continue;
msg.target.dispatchMessage(msg);
MessageQueue.java
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
/**
* 互斥队列的通用类
*/
public class MessageQueue
//声明阻塞队列
private BlockingDeque blockingDeque = new LinkedBlockingDeque(50);
/**
* 入队(生产者)
* @param msg
* @return
*/
public void enqueueMessage(Message msg)
if (msg.target == null)
throw new IllegalArgumentException("Message must have a target.");
try
blockingDeque.put(msg);
System.out.println(Thread.currentThread().getName() + ":msg " + msg.what + " 入队完成");
catch (InterruptedException e)
e.printStackTrace();
/**
* 出队(消费者)
* @return
*/
public Message next()
Message msg = null;
try
System.out.println(Thread.currentThread().getName() + ":MessageQueue.next() ");
msg = (Message) blockingDeque.take();
catch (InterruptedException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
return msg;
Test.java
public class Test
public static void main(String[] args)
Thread androidMain = new Thread(new Runnable()
@Override
public void run()
Looper.prepare();
Handler handler = new Handler()
@Override
public void handleMessage(Message msg)
System.out.println(Thread.currentThread().getName() + ":handleMessage " + msg.what);
;
new Thread(new Runnable()
@Override
public void run()
for (int i = 0; i < 5; i++)
Message message = new Message();
message.what = i;
handler.sendMessage(message);
System.out.println(Thread.currentThread().getName() + "运行结束");
).start();
Looper.loop();
System.out.println(Thread.currentThread().getName() + "结束运行");
, "androidMain");
androidMain.start();
看下运行结果:
从结果中可以得到答案:子线程在所有消息都入队完成后,就结束执行了。主线程一直在运行,Looper#loop()方法体内,已经进入主线程了,无限循环调用MessageQueue#next()方法,next()方法和后面的dispatchMessage()都运行在主线程。
细心的读者会发现,主线程并没退出,这是因为使用了阻塞队列LinkedBlockingDeque。关于阻塞队列,后续再讨论。
从这个手写的Handler,可以发现,MessageQueue的入队方法在子线程中执行,出队方法在主线程中执行。也就是说,同一个对象的不同方法,可以运行在不同的线程中。根据这个原理,我们可以写个更加简单的,子线程给主线程发送消息的例子:
public class SimpleHandler
volatile Message msg; //注意这里的volatiler
public void loopAndHandleMsg()
while (true)
if (msg != null)
System.out.println(Thread.currentThread().getName() + " 处理消息:" + msg.what);
msg = null;
public void sendMsg(Message msg)
while (this.msg != null)
this.msg = msg;
System.out.println(Thread.currentThread().getName() + "消息:" + msg.what+"发送完成");
//Messgae.java文件
public class Message
int what;
Handler target;
//Test.java文件
public class Test
public static void main(String[] args)
Thread androidMain = new Thread(new Runnable()
@Override
public void run()
SimpleHandler simpleHandler = new SimpleHandler();
new Thread(new Runnable()
@Override
public void run()
Message message = new Message();
message.what = 6666;
simpleHandler.sendMsg(message);
Message message2 = new Message();
message2.what = 8888;
simpleHandler.sendMsg(message2);
System.out.println(Thread.currentThread().getName() + "运行结束");
).start();
simpleHandler.loopAndHandleMsg();
System.out.println(Thread.currentThread().getName() + "结束运行");
, "androidMain");
androidMain.start();
运行结果:
继续修改,不再使用volatile,把单个msg改为msgList,如下:
public class SimpleHandler
ArrayList<Message> msgList = new ArrayList<>();
public void loopAndHandleMsg()
while (true)
if (msgList.size()>0)
System.out.println(Thread.currentThread().getName() + " 处理消息:" + msgList.get(msgList.size() - 1).what);
msgList.remove(msgList.size() - 1);
public void sendMsg(Message msg)
msgList.add(0, msg);
System.out.println(Thread.currentThread().getName() + "消息:" + msg.what+"发送完成");
测试代码,子线程连续发送三个消息:
new Thread(new Runnable()
@Override
public void run()
Message message = new Message();
message.what = 6666;
simpleHandler.sendMsg(message);
Message message7 = new Message();
message7.what = 7777;
simpleHandler.sendMsg(message7);
Message message2 = new Message();
message2.what = 8888;
simpleHandler.sendMsg(message2);
System.out.println(Thread.currentThread().getName() + "运行结束");
).start();
再看看运行结果:
线程间通信,就这??????
其实,核心就是:Message的产生、发送、存储都是在子线程完成的,而Message的读取,处理是在主线程完成的。这样看来,是不是觉得Handler也没啥神秘的。
以上是关于Handler到底是怎么实现子线程的Message到主线程下被处理的?的主要内容,如果未能解决你的问题,请参考以下文章