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的关系和之间是如何建立起联系的。

0 0