美文网首页Android相关
Android Looper-ThreadLocal-Threa

Android Looper-ThreadLocal-Threa

作者: LeonXtp | 来源:发表于2018-01-17 13:53 被阅读82次
    关系概述

    looper-threadlocal-thread.png
    • 每个Thread中都有一个ThreadLocal.ThreadLocalMap属性
    • 这个ThreadLocal.ThreadLocalMap属性中保存的是以ThreadLocal为key的类似于HashMap的哈希表,以Entry形式作为结点。
    • 在线程中执行ThreadLocal.set()方法时,都会先获取到当前线程中的ThreadLocalMap,然后以自身(this)为key将数据保存进去。
    • ThreadLocal.get()也是先获取到当前线程中的ThreadLocalMap,然后以自身(this)为key去取值。

    这样,实际上每个线程中都保存一份数据,Looper就是这样保存在自身当前的线程中的。这也是为什么Looper中的sThreadLocalstatic的,却能在不同的线程中获取到自己线程的Looper的原因。
    实际上,真正最重要的角色,是ThreadLocalMap

    上源码

    以下源码基于8.1.0,省去了一些对分析它们关系无关的代码:

    Thread.java:

    class Thread implements Runnable {
    
        ThreadLocal.ThreadLocalMap threadLocals = null;
        
        // ...
    }
    

    ThreadLocal.java

    public class ThreadLocal<T> {
    
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
        public T get() {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
    
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    
        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    
        static class ThreadLocalMap {
    
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
    
            private Entry[] table;
    
            ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
                table = new Entry[INITIAL_CAPACITY];
                //...
                table[i] = new Entry(firstKey, firstValue);
            }
    
            private ThreadLocalMap(ThreadLocalMap parentMap) {
                // ...
            }
    
            private void set(ThreadLocal<?> key, Object value) {
               // ...
            }
    
            private Entry getEntry(ThreadLocal<?> key) {
                // ...
            }
    
    }
    

    Looper.java

    public final class Looper {
    
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        private static Looper sMainLooper;  // guarded by Looper.class
        final MessageQueue mQueue;
    
        public static void prepare() {
            prepare(true);
        }
    
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
        public static void prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
    
        public static Looper getMainLooper() {
            synchronized (Looper.class) {
                return sMainLooper;
            }
        }
    
        public static void loop() {
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
    
            //...
    
            final Looper me = myLooper();
            final MessageQueue queue = me.mQueue;
    
            for (;;) {
                final Looper me = myLooper();
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
      
                // ...
    
                try {
                    msg.target.dispatchMessage(msg);
                }
    
                msg.recycleUnchecked();
            }
        }
    
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    
        public void quit() {
            mQueue.quit(false);
        }
    
    }
    
    

    从以上源码也可以得知为何想要在子线程中使用Handler,一定要先调用Looper.prepare()Looper.loop()方法的原因:

    • 消息循环是在当前的线程中进行循环的
    • 每个线程都有自己的一个消息队列,而这个消息队列在Looper中创建并保存。
    • 于是每个线程都需要保存自己的Looper,这个Looper就是用ThreadLocal保存在了当前线程中
    • 这个保存的操作,就发生在Looper.prepare()方法中。
    • Looper.loop()方法,开启了本线程的消息循环。

    那么Handler是如何实现在不同的线程中通信的?见我这篇:
    Android Handler究竟是如何实现跨线程的?

    相关文章

      网友评论

        本文标题:Android Looper-ThreadLocal-Threa

        本文链接:https://www.haomeiwen.com/subject/yoayoxtx.html