Handler、Looper、MessageQueue源码解析——ThreadLocal


  • 目录
  • Handler、Looper、MessageQueue源码解析——Handler
  • Handler、Looper、MessageQueue源码解析——Looper
  • Handler、Looper、MessageQueue源码解析——ThreadLocal
  • Handler、Looper、MessageQueue源码解析——MessageQueue

ThreadLocal


我们在上一节Looper中在myLooper()中提到可以通过sThreadLocal.get()方法可以得到当前线程的Looper对象,通过ThreadLocal的get()和set()方法,我们可以知道它是以key-value的方式储存变量,所以我们大概可以猜到它的内部实现是一个Map。接下来就来看看它的内部实现。

ThreadLocal有以下几个比较重要的方法:

  • public T get()
  • public void set(T value)
  • protected T initialValue()

我们依次来看一下:

    public T get() {
        //获取当前Thread对象
        Thread t = Thread.currentThread();
        //通过当前Thread对象获得ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }```

果不其然,Map来了,通过当前Thread对象获得一个ThreadLocalMap。ThreadLocalMap是ThreadLocal的一个内部类。

``` java
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }```

threadLocals是Thread的一个成员变量,所以getMap就是从获得Thread对应的ThreadLocalMap对象。

那么ThreadLocalMap是个什么东西呢?

```java
    static class ThreadLocalMap {
        static class Entry extends WeakReference {
        
            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
        }
        private static final int INITIAL_CAPACITY = 16;
        private Entry[] table;
        ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }
        private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];

            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if (e != null) {
                    ThreadLocal key = e.get();
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        int h = key.threadLocalHashCode & (len - 1);
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }

        private Entry getEntry(ThreadLocal key) {
            //通过散列获取Entry的储存位置i
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                //如果直接散列无法获取则遍历整个Map直到找到
                return getEntryAfterMiss(key, i, e);
        }

        private void set(ThreadLocal key, Object value) {

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

        private void remove(ThreadLocal key) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                if (e.get() == key) {
                    e.clear();
                    expungeStaleEntry(i);
                    return;
                }
            }
        }```

所以get()方法获取当前的Thread对象,再通过Thread对象获得ThreadLocalMap对象,然后获取Entry的value,因为ThreadLocal对象是可以传范型的,所以对于Looper来说,得到的是Looper对象。

static final ThreadLocal sThreadLocal = new ThreadLocal();```

所以myLooper()方法得到的是当前线程的Looper对象。

如果得到的ThreadLocalMap为空,则调用setInitialValue():

    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

    protected T initialValue() {
        return null;
    }

initialValue()方法初始返回的是空,如果我们没有重写这个方法,在没有调用set(T value)方法时,我们调用get()方法返回的是null,如果重写了,返回的值就是我们重写的返回值。


说完get(),我们来说说set():

   public void set(T value) {
   //通过当前线程获取ThreadLocalMap
       Thread t = Thread.currentThread();
       ThreadLocalMap map = getMap(t);
   //如果map对象是空,则新建并赋值给Thread的threadLocals,如果不为空则重设
       if (map != null)
           map.set(this, value);
       else
           createMap(t, value);
   }

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

set()方法的代码,一目了然。就是给ThreadLocalMap的value设值。


同时ThreadLocal也有一个remove操作:

``` java
    public void remove() {
        ThreadLocalMap m = getMap(Thread.currentThread());
        if (m != null)
            m.remove(this);
    }

       //获取当前ThreadLocal为key对应的value并移除。
       private void remove(ThreadLocal key) {
           Entry[] tab = table;
           int len = tab.length;
           int i = key.threadLocalHashCode & (len-1);
           for (Entry e = tab[i];
                e != null;
                e = tab[i = nextIndex(i, len)]) {
               if (e.get() == key) {
                   e.clear();
                   expungeStaleEntry(i);
                   return;
               }
           }
       }```

你可能感兴趣的:(Handler、Looper、MessageQueue源码解析——ThreadLocal)