ThreadLocal 的原理分析

ThreadLocal是一个关于创建线程局部变量的类。对于 ThreadLocal 的原理分析,我们从 Android 的Looper类开始分析,我们知道 Looper.myLooper() 会返回当前 Thread 的 Looper。我们就来看看 myLooper() 方法为什么可以返回当前线程的 Looper,而不是其他线程的 Looper。

Looper的主要相关代码如下:

public final class Looper {
    //通过 ThreadLocal 保存当前线程的 Looper
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    ...
    private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            //保存当前线程的 Looper
            sThreadLocal.set(new Looper(quitAllowed));
       }

    //获取当前线程的 Looper
    public static @Nullable Looper myLooper() {
           return sThreadLocal.get();
    }
    ...
}

获取当前线程的 Looper 是通过 ThreadLocal 类的 get() 方法来获取的,我们来看下它的代码实现:

public class ThreadLocal<T> {
    //获取当前线程存储的值
    public T get() {
            //1、获取到当前线程
            Thread t = Thread.currentThread();
            //2、获取当前线程 t 的 ThreadLocalMap 成员变量 map
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                //3、将this 作为 key 得到 entry
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    //4、拿到需要返回的值
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
    }

    //直接返回 thread 的成员变量 threadLocals
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        //第一次 map 为 null,需要调用 createMap 初始化 map。
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
}

ThreadLocalMap 是 ThreadLocal 的一个内部静态类,它是用来保存数据的,它的 getEntry() 方法如下:

static class ThreadLocalMap {
    private Entry getEntry(ThreadLocal<?> key) {
           int i = key.threadLocalHashCode & (table.length - 1);
           Entry e = table[i];
           if (e != null && e.get() == key)
               return e;
           else
               return getEntryAfterMiss(key, i, e);
    }
}

这里的关键是 Thread 类保存了一个成员变量 ThreadLocal.ThreadLocalMap,所以每个线程都有一个 map 来保存值。

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

从上面的流程可以看出 ThreadLocal 类的 get 主要原理步骤就是:

  1. 获取到当前线程
  2. 获取到当前线程的 ThreadLocal.ThreadLocalMap 成员变量
  3. 从成员变量 map 中取值或存值

猜你喜欢

转载自blog.csdn.net/iluojie/article/details/81412636
今日推荐