http://blog.csdn.net/lclansefengbao/article/details/38143411
- 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放到map
- map.set(this, value);
- else
- createMap(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);
- else
- createMap(t, value);
- }
- //删除当前线程的 ThreadLocalMap对象中 key为当前ThreadLocal 的Entry(包含key/value)
- public void remove() {
- ThreadLocalMap m = getMap(Thread.currentThread());
- if (m != null)
- m.remove(this);
- }
- //取得TheadLocalMap
- ThreadLocalMap getMap(Thread t) {
- return t.threadLocals;
- }
- //创建TheadLocalMap
- void 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();
- }
- //静态内部类ThreadLcoalMap
- 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;
- }
- }
- private static final int INITIAL_CAPACITY = 16;
- private Entry[] table;
- private int size = 0;
- private int threshold; // Default to 0
- private 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;
- else
- return 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);
- else
- i = 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 first
- for (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 exists
- if (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 slot
- tab[staleSlot].value = null;
- tab[staleSlot] = new Entry(key, value);
- // If there are any other stale entries in run, expunge them
- if (slotToExpunge != staleSlot)
- cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
- }
- private int expungeStaleEntry(int staleSlot) {
- Entry[] tab = table;
- int len = tab.length;
- // expunge entry at staleSlot
- tab[staleSlot].value = null;
- tab[staleSlot] = null;
- size--;
- // Rehash until we encounter null
- Entry 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 hysteresis
- if (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);
- }
- }
- }
- }