ThreadLocal,Thread,Handler,Looper关系梳理
阅读原文时间:2021年04月20日阅读:1

1,Looper在Thread中用唯一且线程安全的实现原理:

ThreadLocal在某类中被定义,当该类在某线程中运行时,有属于该线程的一个副本,一般定义为static(原因参见:https://www.jianshu.com/p/6f346942ae52)。

如:Looper.java中,如下定义即当一个线程调用Looper的prepare()方法后该线程就有一个Looper变量,该Looper.prepare()在哪个线程执行,即是哪一个线程的Looper:

Looper.java:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    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));
    }

ThreadLocal的get()方法定义见下面源码。

其实现原理为,每个Thread有一个ThreadLocal.ThreadLocalMap类型threadLocals用于存储该线程所有的ThreadLocal变量,其key值即ThreadLocal的类型变量,如上述Looper类型变量,值即为该线程的副本Looper变量。

2,Handler,Looper,ThreadLocal,Thread,MessageQueue关系源码:

public class Handler {
        final android.os.Looper mLooper;
        final MessageQueue mQueue;
        final android.os.Handler.Callback mCallback;
        final boolean mAsynchronous;
        IMessenger mMessenger;

        public Handler() {
            this(null, false);
        }

        public Handler(Callback callback) {
            this(callback, false);
        }

        //* @param looper The looper, must not be null.
        public Handler(Looper looper) {
            this(looper, null, false);
        }

        //* @param looper The looper, must not be null.
        public Handler(Looper looper, Callback callback) {
            this(looper, callback, false);
        }

        public Handler(boolean async) {
            this(null, async);
        }

        //@hide
        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());
                }
            }

            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                        "Can't create handler inside thread that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }

        //@hide
        public Handler(Looper looper, Callback callback, boolean async) {
            mLooper = looper;
            mQueue = looper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    }

public final class Looper {
        // sThreadLocal.get() will return null unless you've called prepare().
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        private static Looper sMainLooper;  // guarded by Looper.class

        final MessageQueue mQueue;
        final Thread mThread;

        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = java.lang.Thread.currentThread();
        }

        /**
         * Returns the application's main looper, which lives in the main thread of the application.
         */
        public static Looper getMainLooper() {
            synchronized (Looper.class) {
                return sMainLooper;
            }
        }

        /**
         * Return the Looper object associated with the current thread.  Returns
         * null if the calling thread is not associated with a Looper.
         */
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    }

public class ThreadLocal<T> {
        /**
         * Creates a thread local variable.
         * @see #withInitial(java.util.function.Supplier)
         */
        public ThreadLocal() {
        }

        /**
         * Returns the value in the current thread's copy of this
         * thread-local variable.  If the variable has no value for the
         * current thread, it is first initialized to the value returned
         * by an invocation of the {@link #initialValue} method.
         *
         * @return the current thread's value of this thread-local
         */
        public T get() {
            java.lang.Thread t = java.lang.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();
        }

        /**
         * Variant of set() to establish initialValue. Used instead
         * of set() in case user has overridden the set() method.
         *
         * @return the initial value
         */
        private T setInitialValue() {
            T value = initialValue();
            java.lang.Thread t = java.lang.Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
            return value;
        }

        /**
         * Sets the current thread's copy of this thread-local variable
         * to the specified value.  Most subclasses will have no need to
         * override this method, relying solely on the {@link #initialValue}
         * method to set the values of thread-locals.
         *
         * @param value the value to be stored in the current thread's copy of
         *        this thread-local.
         */
        public void set(T value) {
            java.lang.Thread t = java.lang.Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }

        /**
         * Removes the current thread's value for this thread-local
         * variable.  If this thread-local variable is subsequently
         * {@linkplain #get read} by the current thread, its value will be
         * reinitialized by invoking its {@link #initialValue} method,
         * unless its value is {@linkplain #set set} by the current thread
         * in the interim.  This may result in multiple invocations of the
         * {@code initialValue} method in the current thread.
         *
         * @since 1.5
         */
        public void remove() {
            ThreadLocalMap m = getMap(java.lang.Thread.currentThread());
            if (m != null)
                m.remove(this);
        }

        /**
         * Get the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param  t the current thread
         * @return the map
         */
        ThreadLocalMap getMap(java.lang.Thread t) {
            return t.threadLocals;
        }

        /**
         * Create the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param t the current thread
         * @param firstValue value for the initial entry of the map
         */
        void createMap(java.lang.Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    }

public class Thread implements Runnable {
        /* ThreadLocal values pertaining to this thread. This map is maintained
         * by the ThreadLocal class. */
        ThreadLocal.ThreadLocalMap threadLocals = null;
    }