源码理会(2)

我们从ThreadLocal.set要领开始阐明:

public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }

set要领将当前线程的副本写入了一个ThreadLocalMap, map的key是当前的ThreadLocal工具。

接下来通过getMap要领阐明这个ThreadLocalMap是如何维护的:

ThreadLocalMap getMap(Thread t) { return t.threadLocals; } public class Thread implements Runnable { ThreadLocal.ThreadLocalMap threadLocals = null; }

每个 Thread 工具维护了一个 ThreadLocalMap 范例的 threadLocals 字段。

ThreadLocalMap 的 key 是 ThreadLocal 工具, 值则是变量的副本, 因此答允一个线程绑定多个 ThreadLocal 工具

领略副本的打点机制后很容易领略get要领:

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

首先获恰当前线程的ThreadLocalMap, 然后从 ThreadLocalMap 实验获恰当前 ThreadLocal 工具对应的副本。

若获取失败,则写入并返回initialValue要领界说的默认值。

Thread.threadLocals 字段是惰性初始化的。 ThreadLocal.set() 要领发明 threadLocals 为空时会挪用 createMap 要领举办初始化, ThreadLocal.get()要领同样会在setInitialValue() 中挪用 createMap 要领初始化 Thread.threadLocals 字段。

为了不影响读者整体相识ThreadLocal, ThreadLocalMap 的实现道理在最后一节ThreadLocalMap

InheritableThreadLocal

InheritableThreadLocal 在子线程建设时将父线程的变量副本通报给子线程。

InheritableThreadLocal 担任了 ThreadLocal 并重写了3个要领, 它利用 Thread.inheritableThreadLocals 取代了 Thread.threadLocals 字段。

public class InheritableThreadLocal<T> extends ThreadLocal<T> { protected T childValue(T parentValue) { return parentValue; } ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; } void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); } }

ThreadLocalMap 的结构器中实现了向子线程通报的逻辑:

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) { @SuppressWarnings("unchecked") ThreadLocal<Object> key = (ThreadLocal<Object>) 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++; } } } }

Thread.init 要领挪用此结构器通报 InheritableThreadLocal:

if (inheritThreadLocals && parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); ThreadLocalMap

值得一提的是, ThreadLocalMap 中利用的是 WeakReference, 当 ThreadLocal 工具不再被外部引用时, 弱引用不会阻止GC因此制止了内存泄露

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; } } /** * The table, resized as necessary. * table.length MUST always be a power of two. */ private Entry[] table; /** * The number of entries in the table. */ private int size = 0; /** * The next size value at which to resize. */ private int threshold; // Default to 0 }

Entry 的 key 始终是 ThreadLocal 工具, 值则是 ThreadLocal 工具绑定的变量副本。

Get 流程

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsdjxw.html