Android多线程基础之从Looper源码深度分析
来源:互联网 发布:淘宝拍摄工作室 编辑:程序博客网 时间:2024/06/15 07:30
谈到Android的多线程,绕不开Looper,首先我们看看一般来说是Android是如何进行线程间通信的:
* <pre> * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }</pre>
首先要有Looper.prepare();
然后new一个Handler
最后Looper.loop();
我们今天就从源码层面深度分析实现原理:
首先看Looper中定义的变量:
private static final String TAG = "Looper"; //利用虚拟机来进行单例的实现,sThreadLocal 应该是存储Looper对象的一个集合 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //主线程的Looper对象 private static Looper sMainLooper; //存储线程发来的Message对象 final MessageQueue mQueue; //当前线程 final Thread mThread;//打印日志有关 private Printer mLogging;
现在我们看Looper.prepare();中做了什么:
public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { //保证一个线程中只有一个Looper对象 //一个线程对应一个Looper if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //给sThreadLocal中添加一个Looper对象 sThreadLocal.set(new Looper(quitAllowed)); }
然后我们看看mHandler = new Handler()是怎样和Looper关联的:
public Handler() { this(null, false); }public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } //通过Looper.myLooper()得到当前线程的Looper对象 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //得到当前线程Looper里面的MessageQueue对象 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
我们再看看Looper.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."); } //得到MessageQueue集合 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 (;;) { //读取MessageQueue集合中的Message 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); } //处理Message 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); } //回收Message msg.recycle(); } }
以上就是整个Thread和Looper的关系;但是里面有几个重要的方法:
mLooper = Looper.myLooper();
这个方法是得到当前线程中的Looper对象:
我们看看源码:
public static Looper myLooper() { //从sThreadLocal中获取 return sThreadLocal.get(); }
结合Looper.prepare中的sThreadLocal.set(new Looper(quitAllowed));
可以看出,不管是获取还是设置Looper对象,都是在sThreadLocal中;
下面重点分析sThreadLocal的实现:
public class ThreadLocal<T> { public ThreadLocal() {}
从定义可以看出,里面有泛型实现的元素我;们先看看set:
public void set(T value) { //和当前线程建立联系 Thread currentThread = Thread.currentThread(); //后面看 Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } //将value添加到values values.put(this, value); }
也就是说,将Looper对象和线程关联以后,存入到Values这个对象中:后面我接着看Values:
先看看定义和变量:
static class Values { private static final int INITIAL_SIZE = 16; private static final Object TOMBSTONE = new Object(); //table是一个Object数组 private Object[] table; private int mask; private int size; private int tombstones; private int maximumLoad; private int clean;
我们在看看:values.put(this, value);
void put(ThreadLocal<?> key, Object value) { cleanUp(); // Keep track of first tombstone. That's where we want to go back // and add an entry if necessary. int firstTombstone = -1; //进入到一个循环中 for (int index = key.hash & mask;; index = next(index)) { Object k = table[index]; //如果之前存在,那么替换 if (k == key.reference) { // Replace existing entry. table[index + 1] = value; return; } //否则,新建一个,然后将value存入到ThreadLocal中 //在Looper中,value其实就是Looper if (k == null) { if (firstTombstone == -1) { // Fill in null slot. table[index] = key.reference; table[index + 1] = value; size++; return; } // Go back and replace first tombstone. table[firstTombstone] = key.reference; table[firstTombstone + 1] = value; tombstones--; size++; return; } // Remember first tombstone. if (firstTombstone == -1 && k == TOMBSTONE) { firstTombstone = index; } } }
其实put就是将Looper对象存储到ThreadLocal对象中的一个Object数组中;加上相应的标记;
我们再看看get
@SuppressWarnings("unchecked") public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { //从Values 中的Object数组中根据标记获取对象 Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } //强转 return (T) values.getAfterMiss(this); }
这下清楚了吧;Looper最后的归宿是在Values中的一个名字叫做table的Object数组中存储;存储的时候添加相关的标记;取的时候根据标记来取;一个Thread中只有一个Looper,一个Looper中有一个MessageQueue,一个MessageQueue中有多个Message;Handler根据Looper来构造,因此一个Thread可以对应多个Handler;以上就是Thread,Looper,MeaageQueue,Handler的关系和之间是如何建立起联系的。
- Android多线程基础之从Looper源码深度分析
- [Android源码]分析之Looper
- android Looper源码分析
- Android 源码分析之Looper 、Handler、 MessageQueue 关系源码分析
- Android--多线程之Looper
- Android--多线程之Looper
- Android从源码分析一:Looper,Handler消息机制
- Android多线程分析之三:Handler,Looper的实现
- Android多线程分析之三:Handler,Looper的实现
- Android多线程之AsyncTask源码分析
- android多线程之AsyncTask源码分析
- 从Handler+Message+Looper源码带你分析Android系统的消息处理机制
- 从Handler+Message+Looper源码带你分析Android系统的消息处理机制
- Android 从源码角度分析消息处理机制(Handler,Looper,Message)
- Android源码分析-消息队列和Looper
- Android源码分析-消息队列和Looper
- Android源码分析-消息队列和Looper
- Android源码分析-消息队列和Looper
- 汇编学习之路(1)CPU 数据传输
- linux下常用mysql命令(3)
- 解决使用Genymotion的Unknown generic error问题
- Objective-C入门 Xcode创建 HalloWorld
- 如何解决MathType 6.9 中公式无法删除的问题
- Android多线程基础之从Looper源码深度分析
- 基于数组实现顺序存储的线性表
- tomcat 访问的重定向问题
- 【c程序】用指针交换两数的值
- 10 个非常重要的 HotSpot JVM 参数
- HTML/CSS 简单布局01
- NDK Application.mk使用手册
- linux命令之grep
- androidstudio 快捷键,使用技巧(持续更新...)