public class ThreadLocalTest implements Runnable { int id; private static final ThreadLocal<HashMap> threadLocal = new ThreadLocal<HashMap>() { @Override protected HashMap initialValue() { return new HashMap(); } };
public ThreadLocalTest(int id) { this.id = id; }
public void run() { Map map=threadLocal.get(); for (int i = 0; i < 20; i++) { map.put(i, i + id * 100); try { Thread.sleep(100); } catch (Exception e) { } } printMap(); }
public static void main(String[] args) { Thread[] runs = new Thread[15]; ThreadLocalTest runnableTest = new ThreadLocalTest(1); for (int i = 0; i < runs.length; i++) { runs[i] = new Thread(runnableTest); } for (int i = 0; i < runs.length; i++) { runs[i].start(); } }
/** * 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. */ staticclassEntryextendsWeakReference<ThreadLocal<?>> {//Entry继承WeakReference,它将以弱引用的方式被持有。 //内部静态类以及弱引用都是防止内存泄漏的有效方式。 /** The value associated with this ThreadLocal. */ Object value;
Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } ...... //构造方法,初始化相关信息 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; //threadLocalHashCode&(INITIAL_CAPACITY - 1),目的是让i小于数组长度。如果每个线程只存一个变量,那么一个key都是一样的。多个变量ThreadLocal变多,要考虑到初始长度。 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); } ...... 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); //如果插入的过程中,产生冲突,这里解决Hash冲突的方式不是链表的方式,而是采用线性探测的方式,根据初始key的hashcode值确定元素在table数组中的位置,如果发现这个位置上已经有其他key值的元素被占用,则利用固定的算法寻找一定步长的下个位置,依次判断,直至找到能够存放的位置。
/** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t){ return t.threadLocals; }
/** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the map */ voidcreateMap(Thread t, T firstValue){ t.threadLocals = new ThreadLocalMap(this, firstValue); }
public T get(){ Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this);//获取Entry if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value;//key是ThreadLocal的hashcode,value是要维护的值 return result; } } return setInitialValue(); }
/** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * * @return the initial value */ 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; }