ThreadLocal原理与应用详解(2)

来源:互联网 发布:福建网络安全教育 编辑:程序博客网 时间:2024/06/06 04:15

2.ThreadLocal实现原理

本文分析源代码基于Android6.0。
代码路径:
libcore/luni/src/main/java/java/lang/ThreadLocal.java
libcore/libart/src/main/java/java/lang/Thread.java

从API官方文档看,ThreadLocal提供了这样一些接口:
public:set()/get()/remove()
protected:initialValue()
从这几个API入手看一下ThreadLocal源代码。

ThreadLocal.java:

    /**     * Sets the value of this variable for the current thread. If set to     * {@code null}, the value will be set to null and the underlying entry will     * still be present.     *     * @param value the new value of the variable for the caller thread.     */    public void set(T value) {        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values == null) {            values = initializeValues(currentThread);        }        values.put(this, value);    }    /**     * Returns the value of this variable for the current thread. If an entry     * doesn't yet exist for this variable on this thread, this method will     * create an entry, populating the value with the result of     * {@link #initialValue()}.     *     * @return the current value of the variable for the calling thread.     */    @SuppressWarnings("unchecked")    public T get() {        // Optimized for the fast path.        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values != null) {            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);    }    /**     * Removes the entry for this variable in the current thread. If this call     * is followed by a {@link #get()} before a {@link #set},     * {@code #get()} will call {@link #initialValue()} and create a new     * entry with the resulting value.     *     * @since 1.5     */    public void remove() {        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values != null) {            values.remove(this);        }    }

梳理一下整个逻辑:
set()/get()/remove(),从当前线程拿到其Values成员变量。Values是定义在ThreadLocal内部的一个包级可见的内部类,是一个类似Map的数据结构,实现从ThreadLocal(作为Key)到Object(作为Value)的映射。在Thread中,只定义了这样一个包级可见的成员变量,没有任何的维护逻辑,维护逻辑都在ThreadLocal中。
上面是大概框架,下面从一些点来仔细研究其实现机制。

2.1ThreadLocal对于Thread.localValues的维护

ThreadLocal得到当前线程的Values方法如下:

    /**     * Gets Values instance for this thread and variable type.     */    Values values(Thread current) {        return current.localValues;    }

Thread.java:

    /**     * Normal thread local values.     */    ThreadLocal.Values localValues;

在Thread中,只定义了这样一个包级可见的成员变量,没有任何的维护逻辑,维护逻辑都在ThreadLocal中。

(1)初始化
values()方法获取到localValues的引用,如果发现尚为null,通过initializeValues()初始化

    /**     * Creates Values instance for this thread and variable type.     */    Values initializeValues(Thread current) {        return current.localValues = new Values();    }

接下来看看Values类的构造方法

        /**         * Constructs a new, empty instance.         */        Values() {            initializeTable(INITIAL_SIZE);            this.size = 0;            this.tombstones = 0;        }        /**         * Used for InheritableThreadLocals.         */        Values(Values fromParent) {            this.table = fromParent.table.clone();            this.mask = fromParent.mask;            this.size = fromParent.size;            this.tombstones = fromParent.tombstones;            this.maximumLoad = fromParent.maximumLoad;            this.clean = fromParent.clean;            inheritValues(fromParent);        }

前者比较简单。后者是从一个Parent Values对象创建一个新的Values对象,应用于InheritableThreadLocal。继承稍后介绍。

(2)继承
InheritableThreadLocal是ThreadLocal的一个子类,这里不扩展介绍。继续看看Values的inheritValues()方法

        /**         * Inherits values from a parent thread.         */        @SuppressWarnings({"unchecked"})        private void inheritValues(Values fromParent) {            // Transfer values from parent to child thread.            Object[] table = this.table;            for (int i = table.length - 2; i >= 0; i -= 2) {                Object k = table[i];                if (k == null || k == TOMBSTONE) {                    // Skip this entry.                    continue;                }                // The table can only contain null, tombstones and references.                Reference<InheritableThreadLocal<?>> reference                        = (Reference<InheritableThreadLocal<?>>) k;                // Raw type enables us to pass in an Object below.                InheritableThreadLocal key = reference.get();                if (key != null) {                    // Replace value with filtered value.                    // We should just let exceptions bubble out and tank                    // the thread creation                    table[i + 1] = key.childValue(fromParent.table[i + 1]);                } else {                    // The key was reclaimed.                    table[i] = TOMBSTONE;                    table[i + 1] = null;                    fromParent.table[i] = TOMBSTONE;                    fromParent.table[i + 1] = null;                    tombstones++;                    fromParent.tombstones++;                    size--;                    fromParent.size--;                }            }        }

这个方法的作用即从父Thread继承线程本地变量值。

原创粉丝点击