ThreadLocal
类主要解决的就是让每个线程绑定自己的值,可以存储每个线程的私有数据。
如果你创建了一个ThreadLocal
变量,那么访问这个变量的每个线程都会有这个变量的本地副本。
Thread 类
public class Thread implements Runnable { //...... //与此线程有关的ThreadLocal值。由ThreadLocal类维护 ThreadLocal.ThreadLocalMap threadLocals = null; //与此线程有关的InheritableThreadLocal值。由InheritableThreadLocal类维护 ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; //...... }
ThreadLocal 类的 set() 方法
public void set(T value) { //获取当前请求的线程 Thread t = Thread.currentThread(); //取出 Thread 类内部的 threadLocals 变量(哈希表结构) ThreadLocalMap map = getMap(t); if (map != null) // 将需要存储的值放入到这个哈希表中 map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
最终的变量是放在了当前线程的 ThreadLocalMap
中,并不是存在 ThreadLocal
上,ThreadLocal
可以理解为只是ThreadLocalMap
的封装,传递了变量值。 ThrealLocal
类中可以通过Thread.currentThread()
获取到当前线程对象后,直接通过getMap(Thread t)
可以访问到该线程的ThreadLocalMap
对象。
ThreadLocal 使用示例
ThreadLocalMap 类的定义在 ThreadLocal<T> 类中,是 ThreadLocal 类的一个内部类, key 是 ThreadLocal<T> 的一个对象,value 是这个 <T> 的实际值
Thread 线程类有一个字段,ThreadLocal.ThreadLocalMap threadLocals = null,是 ThreadLocal.ThreadLocalMap 类的一个实现对象,也就是每个线程对象都有一个 ThreadLocalMap 对象
ThreadLocal<T> 相当于一个维护所有线程 ThreadLocal.ThreadLocalMap threadLocals = null 这个属性,即所有线程 <T> 的取值 value 的一个工具类
下面用一个例子说明这一点
import dto.TreeNode; import java.util.Random; public class testThreadLocal implements Runnable{ private static final ThreadLocal<TreeNode> treeNodeThreadLocal = new ThreadLocal<>(); private static final ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<>().withInitial(() -> 0); public static void main(String[] args) throws InterruptedException { testThreadLocal thisclass = new testThreadLocal(); for(int i=0 ; i<10; i++){ Thread t = new Thread(thisclass, ""+i); Thread.sleep(new Random().nextInt(1000)); t.start(); } } @Override public void run() { System.out.println("Thread Name= "+Thread.currentThread().getName()+" integerThreadLocal = "+ integerThreadLocal.get()); Integer curThreadInt = new Random().nextInt(1000); treeNodeThreadLocal.set(new TreeNode(curThreadInt, Thread.currentThread().getName())); integerThreadLocal.set(curThreadInt); System.out.println("Thread Name= "+Thread.currentThread().getName() +" integerThreadLocal = "+integerThreadLocal.get() +" treeNodeThreadLocal = "+treeNodeThreadLocal.get()); } }
输出结果如下
treeNodeThreadLocal 和 integerThreadLocal 这两个 ThreadLocal 类的对象与线程的关系如下所示
ThreadLocal. ThreadLocalMap 内部类定义
/** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } /** * The initial capacity -- MUST be a power of two. */ private static final int INITIAL_CAPACITY = 16; /** * 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 /** * Set the resize threshold to maintain at worst a 2/3 load factor. */ private void setThreshold(int len) { threshold = len * 2 / 3; } /** * Increment i modulo len. */ private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); } /** * Decrement i modulo len. */ private static int prevIndex(int i, int len) { return ((i - 1 >= 0) ? i - 1 : len - 1); } /** * Construct a new map initially containing (firstKey, firstValue). * ThreadLocalMaps are constructed lazily, so we only create * one when we have at least one entry to put in it. */ 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); } /** * Construct a new map including all Inheritable ThreadLocals * from given parent map. Called only by createInheritedMap. * * @param parentMap the map associated with parent thread. */ 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++; } } } } /** * Get the entry associated with key. This method * itself handles only the fast path: a direct hit of existing * key. It otherwise relays to getEntryAfterMiss. This is * designed to maximize performance for direct hits, in part * by making this method readily inlinable. * * @param key the thread local object * @return the entry associated with key, or null if no such */ 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); } // ...... 后面的就不贴过来了
标签:ThreadLocalMap,int,ThreadLocal,线程,key,table From: https://www.cnblogs.com/suBlog/p/17547959.html