源码分析 — Handler机制(线程间通信)
2018-01-02 15:11
260 查看
最近整理以前的文章,上传到CSDN。
MessageQueue:消息队列。负责存放一个线程的Message和Runnable的集合。
Message:消息实体类。
Looper:消息轮询器。负责将MessageQueue中的Message或Runnable循环取出来,然后分发到Handler中。
一个线程可以有多个Handler实例,
一个线程只能有一个Looper和MessageQueue,
一个MessageQueue对应多个Message和Runnable。
一对多的关系:
一方:Looper和MessageQueue
多方:Handler、Message和Runnable
问题: 为什么说一个线程对应一个Looper实例?
分析: 查看Looper.myLooper()源码
同时,所有的线程都共享一个ThreadLocal对象,但是不同的线程会有对应不同的value,且单独修改某一个线程值时不影响其它线程值,并支持null值。
小结: 每个线程都会存放一个独立的Looper实例,通过ThreadLocal.get()方法,就会获得当前线程的Looper实例。
问题: Handler是如何发生Runnable的呢?
分析:
小结:其实传入的Runnable对象都是封装到Message类中。
问题: 那么Message中存放哪些信息呢?
分析: Message.obtain()是获取断掉的Message链关系的第一个Message。
1. Message.obtain()是通过从全局Message sPool中读取一个Message,回收的时候也是将Message放入到mPool中。
2. Message中实现了Parcelable接口。
问题: Handler是如何发生Message的呢?
分析:
小结: 当按时间发送时,无论是发送Message还是Runnable,最终调用的都是sendMessageAtTime()方法,里面的核心方法是enqueueMessage()方法,该方法就是调用MessageQueue中的enqueueMessage()方法,其实就是将Message加入到消息队列中。
问题: 如果发送消息只是将消息加入到消息队列中,那谁来把消息分发到Handler中呢?
分析:
小结:
在Looper类的loop()方法中调用Handler的dispatchMessage(msg)方法,在dispatchMessage(msg)内部最终调用了handlerMessage(msg)。
换句话说,Looper.loop()方法就是取得当前线程中的MessageQueue实例,然后不断循环获取消息,并将消息分发到对应的Handler实例上。
实质上只要调用Looper.loop()方法,就可以执行消息分发。
整个机制实现原理流程:
当应用程序运行时,会创建一个Linux进程和一个UI线程(ActivityThread),这个类里有一个main方法,是Java程序运行最开始的入口。
小结: UI线程一执行就已经调用了loop消息分发,所以当在UI线程中通过Handler对象发送消息或者任务时,会把Message加入到MessageQueue消息队列中,然后分发到Handler的handlerMessage方法里。
分析: 其实就是在子线程中实现handler.handleMessage()方法的调用。
小结: 通过查看HandlerThread源码,发现HandlerThread继承自Thread类,从run()方法中可以发现,HandlerThread要调用start()方法,才能实例化HandlerThread的Looper对象和实现消息分发功能。
所以,要使用HandlerThread,必须先运行HandlerThread,这样才能取出对应的Looper对象,然后使用Handler(Looper)构造方法实例化Handler(即实现Handler和Looper的关联),这时handler就可以再子线程中执行handlerMessage()方法了。
与Handler+Message+Thread的区别:HandlerThread类里面处理Message消息可以是耗时操作,但是不能对UI操作,即handleMessage()方法只能在子线程中执行;
例子:
重写run()方法,并在该方法内部实现以下三个方法
Looper.prepare(); //将Looper设置到这个线程中
Looper mLooper = Looper.myLooper();
Looper.loop(); //开启消息循环
在另一个类中创建出该线程类对象,并启动线程;
创建一个Handler类进行线程和Looper绑定;
发送消息;
处理消息;
一、前言
线程间通讯机制的内部实现原理,即Handler、
Message、
MessageQueue、
Looper、
HandlerThread、
AsyncTask类的实现以及之间的关系。
二、了解相关的几个类:
Handler:负责发送Message和Runnable到MessageQueue中,然后依次处理MessageQueue队列里的消息。MessageQueue:消息队列。负责存放一个线程的Message和Runnable的集合。
Message:消息实体类。
Looper:消息轮询器。负责将MessageQueue中的Message或Runnable循环取出来,然后分发到Handler中。
小结:
这四者的关系:一个线程可以有多个Handler实例,
一个线程只能有一个Looper和MessageQueue,
一个MessageQueue对应多个Message和Runnable。
一对多的关系:
一方:Looper和MessageQueue
多方:Handler、Message和Runnable
三、主线程和子线程之间的通信
3.1 Handler类
当实例化一个Handler对象时,就完成了Handler实例与一个线程和一个消息队列的绑定。/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { ······ //获取Looper对象 mLooper = Looper.myLooper(); ······ //获取消息队列实体 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
问题: 为什么说一个线程对应一个Looper实例?
分析: 查看Looper.myLooper()源码
//-------------------ThreadLacal类---------------------- // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static Looper myLooper() { return sThreadLocal.get();//获得当前线程的Looper实例。 }
3.2 ThreadLocal类
这个类实现了一个线程的本地存储,即每个线程都会有自己的内存空间来存放线程自己的值。同时,所有的线程都共享一个ThreadLocal对象,但是不同的线程会有对应不同的value,且单独修改某一个线程值时不影响其它线程值,并支持null值。
小结: 每个线程都会存放一个独立的Looper实例,通过ThreadLocal.get()方法,就会获得当前线程的Looper实例。
问题: Handler是如何发生Runnable的呢?
分析:
//-------------------Handler类------------------- public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; //将Runnable对象当作msg中的callback属性传入; return m; }
小结:其实传入的Runnable对象都是封装到Message类中。
问题: 那么Message中存放哪些信息呢?
分析: Message.obtain()是获取断掉的Message链关系的第一个Message。
1. Message.obtain()是通过从全局Message sPool中读取一个Message,回收的时候也是将Message放入到mPool中。
2. Message中实现了Parcelable接口。
public final class Message implements Parcelable { public int what; public int arg1; public int arg2; public Object obj; public Messenger replyTo; static final int FLAG_IN_USE = 1 << 0; static final int FLAG_ASYNCHRONOUS = 1 << 1; static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; int flags; long when; //向Handler发送Message生成的时间 Bundle data; //在Bundler对象上绑定要在线程中传递的数据 Handler target; //处理当前Message的Handler对象 Runnable callback; Message next; //当前Message对下一个Message的引用 private static final Object sPoolSync = new Object(); private static Message sPool; //有下一个Message引用的Message链(Message池) private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); } }
问题: Handler是如何发生Message的呢?
分析:
//-------------------------Handler类---------------------------- public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { // this代表Handler msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
小结: 当按时间发送时,无论是发送Message还是Runnable,最终调用的都是sendMessageAtTime()方法,里面的核心方法是enqueueMessage()方法,该方法就是调用MessageQueue中的enqueueMessage()方法,其实就是将Message加入到消息队列中。
问题: 如果发送消息只是将消息加入到消息队列中,那谁来把消息分发到Handler中呢?
分析:
//------------------------Looper类--------------------------- /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { //获取一个Looper对象 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //获取Looper里的消息队列 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); } //消息分发 handler.dispatchMessage(msg),将消息从轮询器中取出发送到对应的handler中 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.recycle();//释放消息占据的资源 } } //----------------------Handler类--------------------------- /** * Handle system messages here. */ public void dispatchMessage(Message msg) { //msg.callback其实就是传入的Runnable对象; if (msg.callback != null) { //如果handler传入的值是Runnable,则直接执行callback回调 handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //Callback接口,具体业务处理在这里执行 handleMessage(msg); } }
小结:
在Looper类的loop()方法中调用Handler的dispatchMessage(msg)方法,在dispatchMessage(msg)内部最终调用了handlerMessage(msg)。
换句话说,Looper.loop()方法就是取得当前线程中的MessageQueue实例,然后不断循环获取消息,并将消息分发到对应的Handler实例上。
实质上只要调用Looper.loop()方法,就可以执行消息分发。
四、Handler、Message、MessageQueue、Looper的关系原理图:
整个机制实现原理流程:
当应用程序运行时,会创建一个Linux进程和一个UI线程(ActivityThread),这个类里有一个main方法,是Java程序运行最开始的入口。
//-----------------------ActivityThread类--------------------------- public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Process.setArgV0("<pre‐initialized>"); //由framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的 Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } //创建主线程 ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } //获取MessageQueue实例,执行消息分发 Looper.loop() throw new RuntimeException("Main thread loop unexpectedly exited"); } ActivityThread() { ...省略代码... }
小结: UI线程一执行就已经调用了loop消息分发,所以当在UI线程中通过Handler对象发送消息或者任务时,会把Message加入到MessageQueue消息队列中,然后分发到Handler的handlerMessage方法里。
五、子线程之间的线程通信
问题: 如何实现子线程之间的线程通信?分析: 其实就是在子线程中实现handler.handleMessage()方法的调用。
//----------------------Thread类---------------------------- public Thread(String threadName) { if (threadName == null) { throw new NullPointerException("threadName == null"); } //创建一个子线程 create(null, null, threadName, 0); } //--------------------------HandlerThread类------------------------------- /** * Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called. */ public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); //调用Thread(String threadName) mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */ protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); //Initialize the current thread as a looper. Looper.prepare(); synchronized (this) { //实例化Looper对象 mLooper = Looper.myLooper(); notifyAll();//Object类中的本地方法(native) } Process.setThreadPriority(mPriority); onLooperPrepared(); //内部实现消息分发功能 Looper.loop(); mTid = -1; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } /** * Quits the handler thread's looper. * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. * @see #quitSafely */ public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } /** * Quits the handler thread's looper safely. * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. */ public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; } }
小结: 通过查看HandlerThread源码,发现HandlerThread继承自Thread类,从run()方法中可以发现,HandlerThread要调用start()方法,才能实例化HandlerThread的Looper对象和实现消息分发功能。
所以,要使用HandlerThread,必须先运行HandlerThread,这样才能取出对应的Looper对象,然后使用Handler(Looper)构造方法实例化Handler(即实现Handler和Looper的关联),这时handler就可以再子线程中执行handlerMessage()方法了。
HandlerThread类
自身继承Thread,是一个子线程;与Handler+Message+Thread的区别:HandlerThread类里面处理Message消息可以是耗时操作,但是不能对UI操作,即handleMessage()方法只能在子线程中执行;
例子:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); HandlerThread mThread = new HandlerThread("myThread"); //先调用start(启动一个线程 mThread.start(); //调用Handler(Looper)方法实例化一个Handler对象 myHandler myHandler = new myHandler(mThread.getLooper()); Message msg = myHandler.obtainMessage(); //把Message发送到目标对象,目标对象就是生成msg的目标对象。 msg.sendToTarget(); //实际上方法内部调用handler.sendMessage(msg); } class myHandler extends Handler { //必须调用Handler(Looper looper)方法 public myHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { Log.e("这是新线程", ">>>>>>>新线程的测试"); } }
六、自己实现一个可以处理消息的子线程:(模仿HandlerThread)
自定义一个线程类继承Thread类;重写run()方法,并在该方法内部实现以下三个方法
Looper.prepare(); //将Looper设置到这个线程中
Looper mLooper = Looper.myLooper();
Looper.loop(); //开启消息循环
在另一个类中创建出该线程类对象,并启动线程;
创建一个Handler类进行线程和Looper绑定;
发送消息;
处理消息;
相关文章推荐
- 源码分析Android Handler是如何实现线程间通信的
- Android线程间异步通信机制源码分析
- Android Handler如何实现线程间通信,源码分析。
- 源码分析Android Handler是如何实现线程间通信的
- [netty源码分析]--EventLoopGroup与EventLoop 分析netty的线程模型
- 音频通信源码分析
- 源码分析glide对线程中断的优化
- Quartz源码分析(一)------ 以线程等待的方式实现按时间调度
- DotNetty网络通信框架学习之源码分析
- lua 源码分析之线程对象lua_State
- 基于TCP网络通信的自动升级程序源码分析--生成升级文件相关的配置文件
- Memcached源码分析(线程模型)
- muduo源码分析--buffer中的线程安全
- android线程通信基础分析
- Netty5源码分析(二) -- 线程模型分析
- LDD3源码分析之与硬件通信&中断处理
- Nginx源码分析-master和worker进程间的通信
- 【Netty源码分析】Reactor线程模型
- 【深入分析Java多线程】(6)线程间通信之wait()、notify()、join()
- rt-thread的空闲线程源码分析