LClansefengbao的专栏

本文通过对ThreadLocal源码(jdk1.7)解析来加深对ThreaLocal类理解

源代码如下:

package java.lang;import java.lang.ref.*;import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocal<T> {private final int threadLocalHashCode = nextHashCode(); //ThreadLocal实例hash值,用来区分不同实例private static AtomicInteger nextHashCode =//可以看作hash值的一个基值new AtomicInteger();private static final int HASH_INCREMENT = 0x61c88647; //hash值每次增加量private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);}//初始化函数protected T initialValue() {return null;}//无参构造函数public ThreadLocal() {}//注意:每个线程中都是有一个ThreadLocalMap对象,它属于Map类型,其中key为ThreadLocal对象,value为某个对象。 //从当前线程的ThreadLocalMap中取出 key为当前ThreadLocal对象 的value对象,其实key值与ThreadLocal的threadLocalHashCode值有关public T get() {Thread t = Thread.currentThread(); //得到当前线程ThreadLocalMap map = getMap(t);//得到当前线程的ThreadLocalMap对象if (map != null) {//如果map不为null,ThreadLocalMap.Entry e = map.getEntry(this); //得到map中Entry实体对象;if (e != null) //如果e不为空,,则取出Entry对象中的value值,然后返回return (T)e.value;}return setInitialValue(); //如果map为null,则创建ThreadLocalMap对象,//并且创建一个空的T对象放到map中,最后返回null}private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread(); //得到当前线程ThreadLocalMap map = getMap(t); //得到当前线程的ThreadLocalMap对象if (map != null)//map不为空,则将value放到mapmap.set(this, value);elsecreateMap(t, value); //否则创建map,然后将value放到map中return value;}//把value放到当前线程的ThreadLocalMap对象中去,其中key值与当前ThreadLocal对象的threadLocalHashCode值有关public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}//删除当前线程的 ThreadLocalMap对象中 key为当前ThreadLocal 的Entry(包含key/value)public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);}//取得TheadLocalMapThreadLocalMap getMap(Thread t) {return t.threadLocals;}//创建TheadLocalMapvoid createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);}static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {return new ThreadLocalMap(parentMap);}T childValue(T parentValue) {throw new UnsupportedOperationException();}//静态内部类ThreadLcoalMapstatic 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;}}private static final int INITIAL_CAPACITY = 16;private Entry[] table;private int size = 0;private int threshold; // Default to 0private void setThreshold(int len) {threshold = len * 2 / 3;}private static int nextIndex(int i, int len) {return ((i + 1 < len) ? i + 1 : 0);}private static int prevIndex(int i, int len) {return ((i – 1 >= 0) ? i – 1 : len – 1);}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) {int i = key.threadLocalHashCode & (table.length – 1);Entry e = table[i];if (e != null && e.get() == key)return e;elsereturn getEntryAfterMiss(key, i, e);}private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) {Entry[] tab = table;int len = tab.length;while (e != null) {ThreadLocal k = e.get();if (k == key)return e;if (k == null)expungeStaleEntry(i);elsei = nextIndex(i, len);e = tab[i];}return null;}private void set(ThreadLocal key, Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.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;}}}private void replaceStaleEntry(ThreadLocal key, Object value,int staleSlot) {Entry[] tab = table;int len = tab.length;Entry e;// Back up to check for prior stale entry in current run.// We clean out whole runs at a time to avoid continual// incremental rehashing due to garbage collector freeing// up refs in bunches (i.e., whenever the collector runs).int slotToExpunge = staleSlot;for (int i = prevIndex(staleSlot, len);(e = tab[i]) != null;i = prevIndex(i, len))if (e.get() == null)slotToExpunge = i;// Find either the key or trailing null slot of run, whichever// occurs firstfor (int i = nextIndex(staleSlot, len);(e = tab[i]) != null;i = nextIndex(i, len)) {ThreadLocal k = e.get();// If we find key, then we need to swap it// with the stale entry to maintain hash table order.// The newly stale slot, or any other stale slot// encountered above it, can then be sent to expungeStaleEntry// to remove or rehash all of the other entries in run.if (k == key) {e.value = value;tab[i] = tab[staleSlot];tab[staleSlot] = e;// Start expunge at preceding stale entry if it existsif (slotToExpunge == staleSlot)slotToExpunge = i;cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);return;}// If we didn't find stale entry on backward scan, the// first stale entry seen while scanning for key is the// first still present in the run.if (k == null && slotToExpunge == staleSlot)slotToExpunge = i;}// If key not found, put new entry in stale slottab[staleSlot].value = null;tab[staleSlot] = new Entry(key, value);// If there are any other stale entries in run, expunge themif (slotToExpunge != staleSlot)cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);}private int expungeStaleEntry(int staleSlot) {Entry[] tab = table;int len = tab.length;// expunge entry at staleSlottab[staleSlot].value = null;tab[staleSlot] = null;size–;// Rehash until we encounter nullEntry e;int i;for (i = nextIndex(staleSlot, len);(e = tab[i]) != null;i = nextIndex(i, len)) {ThreadLocal k = e.get();if (k == null) {e.value = null;tab[i] = null;size–;} else {int h = k.threadLocalHashCode & (len – 1);if (h != i) {tab[i] = null;// Unlike Knuth 6.4 Algorithm R, we must scan until// null because multiple entries could have been stale.while (tab[h] != null)h = nextIndex(h, len);tab[h] = e;}}}return i;}private boolean cleanSomeSlots(int i, int n) {boolean removed = false;Entry[] tab = table;int len = tab.length;do {i = nextIndex(i, len);Entry e = tab[i];if (e != null && e.get() == null) {n = len;removed = true;i = expungeStaleEntry(i);}} while ( (n >>>= 1) != 0);return removed;}private void rehash() {expungeStaleEntries();// Use lower threshold for doubling to avoid hysteresisif (size >= threshold – threshold / 4)resize();}private void resize() {Entry[] oldTab = table;int oldLen = oldTab.length;int newLen = oldLen * 2;Entry[] newTab = new Entry[newLen];int count = 0;for (int j = 0; j < oldLen; ++j) {Entry e = oldTab[j];if (e != null) {ThreadLocal k = e.get();if (k == null) {e.value = null; // Help the GC} else {int h = k.threadLocalHashCode & (newLen – 1);while (newTab[h] != null)h = nextIndex(h, newLen);newTab[h] = e;count++;}}}setThreshold(newLen);size = count;table = newTab;}private void expungeStaleEntries() {Entry[] tab = table;int len = tab.length;for (int j = 0; j < len; j++) {Entry e = tab[j];if (e != null && e.get() == null)expungeStaleEntry(j);}}}}

理想的路总是为有信心的人预备着

LClansefengbao的专栏

相关文章:

你感兴趣的文章:

标签云: