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到主线程下被处理的?的主要内容,如果未能解决你的问题,请参考以下文章

Android 中handler消息机制的理解

android通过Handler使子线程更新UI

主线程不能执行耗时的操作,子线程不能更新Ui

Android中Handler的主要作用是啥?通俗点,初学。

Android——Handler详解

Handler