JDK源码解析之ThreadLocal类

http://blog.csdn.net/lclansefengbao/article/details/38143411


[java]  view plain copy
  1. package java.lang;  
  2. import java.lang.ref.*;  
  3. import java.util.concurrent.atomic.AtomicInteger;  
  4.   
  5. public class ThreadLocal<T> {  
  6.   
  7.     private final int threadLocalHashCode = nextHashCode();  //ThreadLocal实例hash值,用来区分不同实例  
  8.   
  9.     private static AtomicInteger nextHashCode =         //可以看作hash值的一个基值  
  10.         new AtomicInteger();  
  11.   
  12.     private static final int HASH_INCREMENT = 0x61c88647;   //hash值每次增加量  
  13.   
  14.     private static int nextHashCode() {  
  15.         return nextHashCode.getAndAdd(HASH_INCREMENT);  
  16.     }  
  17.     //初始化函数  
  18.     protected T initialValue() {    
  19.         return null;  
  20.     }  
  21.     //无参构造函数  
  22.     public ThreadLocal() {  
  23.     }  
  24.     //注意:每个线程中都是有一个ThreadLocalMap对象,它属于Map类型,其中key为ThreadLocal对象,value为某个对象。  
  25.    //从当前线程的ThreadLocalMap中取出 key为当前ThreadLocal对象 的value对象,其实key值与ThreadLocal的threadLocalHashCode值有关  
  26.     public T get() {  
  27.         Thread t = Thread.currentThread();   //得到当前线程  
  28.         ThreadLocalMap map = getMap(t);     //得到当前线程的ThreadLocalMap对象  
  29.         if (map != null) {      //如果map不为null,  
  30.             ThreadLocalMap.Entry e = map.getEntry(this);  //得到map中Entry实体对象;  
  31.             if (e != null)   //如果e不为空,则取出Entry对象中的value值,然后返回  
  32.                 return (T)e.value;  
  33.         }  
  34.         return setInitialValue();  //如果map为null,则创建ThreadLocalMap对象,  
  35.                                    //并且创建一个空的T对象放到map中,最后返回null  
  36.     }  
  37.   
  38.   
  39.     private T setInitialValue() {  
  40.         T value = initialValue();     
  41.         Thread t = Thread.currentThread();  //得到当前线程  
  42.         ThreadLocalMap map = getMap(t);  //得到当前线程的ThreadLocalMap对象  
  43.         if (map != null)          //map不为空,则将value放到map  
  44.             map.set(this, value);  
  45.         else  
  46.             createMap(t, value);   //否则创建map,然后将value放到map中  
  47.         return value;  
  48.     }  
  49.     //把value放到当前线程的ThreadLocalMap对象中去,其中key值与当前ThreadLocal对象的threadLocalHashCode值有关  
  50.     public void set(T value) {  
  51.         Thread t = Thread.currentThread();  
  52.         ThreadLocalMap map = getMap(t);  
  53.         if (map != null)  
  54.             map.set(this, value);  
  55.         else  
  56.             createMap(t, value);  
  57.     }  
  58.     //删除当前线程的 ThreadLocalMap对象中 key为当前ThreadLocal 的Entry(包含key/value)  
  59.     public void remove() {  
  60.          ThreadLocalMap m = getMap(Thread.currentThread());  
  61.          if (m != null)  
  62.              m.remove(this);  
  63.      }  
  64.   
  65.     //取得TheadLocalMap  
  66.     ThreadLocalMap getMap(Thread t) {  
  67.         return t.threadLocals;  
  68.     }  
  69.   
  70.     //创建TheadLocalMap  
  71.     void createMap(Thread t, T firstValue) {  
  72.         t.threadLocals = new ThreadLocalMap(this, firstValue);  
  73.     }  
  74.   
  75.   
  76.     static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {  
  77.         return new ThreadLocalMap(parentMap);  
  78.     }  
  79.   
  80.   
  81.     T childValue(T parentValue) {  
  82.         throw new UnsupportedOperationException();  
  83.     }  
  84.     //静态内部类ThreadLcoalMap  
  85.     static class ThreadLocalMap {  
  86.   
  87.         static class Entry extends WeakReference<ThreadLocal> {  
  88.             /** The value associated with this ThreadLocal. */  
  89.             Object value;  
  90.   
  91.             Entry(ThreadLocal k, Object v) {  
  92.                 super(k);  
  93.                 value = v;  
  94.             }  
  95.         }  
  96.   
  97.         private static final int INITIAL_CAPACITY = 16;  
  98.   
  99.   
  100.         private Entry[] table;  
  101.   
  102.         private int size = 0;  
  103.   
  104.         private int threshold; // Default to 0  
  105.   
  106.         private void setThreshold(int len) {  
  107.             threshold = len * 2 / 3;  
  108.         }  
  109.   
  110.         private static int nextIndex(int i, int len) {  
  111.             return ((i + 1 < len) ? i + 1 : 0);  
  112.         }  
  113.   
  114.         private static int prevIndex(int i, int len) {  
  115.             return ((i - 1 >= 0) ? i - 1 : len - 1);  
  116.         }  
  117.   
  118.         ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {  
  119.             table = new Entry[INITIAL_CAPACITY];  
  120.             int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);  
  121.             table[i] = new Entry(firstKey, firstValue);  
  122.             size = 1;  
  123.             setThreshold(INITIAL_CAPACITY);  
  124.         }  
  125.   
  126.         private ThreadLocalMap(ThreadLocalMap parentMap) {  
  127.             Entry[] parentTable = parentMap.table;  
  128.             int len = parentTable.length;  
  129.             setThreshold(len);  
  130.             table = new Entry[len];  
  131.   
  132.             for (int j = 0; j < len; j++) {  
  133.                 Entry e = parentTable[j];  
  134.                 if (e != null) {  
  135.                     ThreadLocal key = e.get();  
  136.                     if (key != null) {  
  137.                         Object value = key.childValue(e.value);  
  138.                         Entry c = new Entry(key, value);  
  139.                         int h = key.threadLocalHashCode & (len - 1);  
  140.                         while (table[h] != null)  
  141.                             h = nextIndex(h, len);  
  142.                         table[h] = c;  
  143.                         size++;  
  144.                     }  
  145.                 }  
  146.             }  
  147.         }  
  148.   
  149.         private Entry getEntry(ThreadLocal key) {  
  150.             int i = key.threadLocalHashCode & (table.length - 1);  
  151.             Entry e = table[i];  
  152.             if (e != null && e.get() == key)  
  153.                 return e;  
  154.             else  
  155.                 return getEntryAfterMiss(key, i, e);  
  156.         }  
  157.   
  158.   
  159.         private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) {  
  160.             Entry[] tab = table;  
  161.             int len = tab.length;  
  162.   
  163.             while (e != null) {  
  164.                 ThreadLocal k = e.get();  
  165.                 if (k == key)  
  166.                     return e;  
  167.                 if (k == null)  
  168.                     expungeStaleEntry(i);  
  169.                 else  
  170.                     i = nextIndex(i, len);  
  171.                 e = tab[i];  
  172.             }  
  173.             return null;  
  174.         }  
  175.   
  176.         private void set(ThreadLocal key, Object value) {  
  177.   
  178.             // We don't use a fast path as with get() because it is at  
  179.             // least as common to use set() to create new entries as  
  180.             // it is to replace existing ones, in which case, a fast  
  181.             // path would fail more often than not.  
  182.   
  183.             Entry[] tab = table;  
  184.             int len = tab.length;  
  185.             int i = key.threadLocalHashCode & (len-1);  
  186.   
  187.             for (Entry e = tab[i];  
  188.                  e != null;  
  189.                  e = tab[i = nextIndex(i, len)]) {  
  190.                 ThreadLocal k = e.get();  
  191.   
  192.                 if (k == key) {  
  193.                     e.value = value;  
  194.                     return;  
  195.                 }  
  196.   
  197.                 if (k == null) {  
  198.                     replaceStaleEntry(key, value, i);  
  199.                     return;  
  200.                 }  
  201.             }  
  202.   
  203.             tab[i] = new Entry(key, value);  
  204.             int sz = ++size;  
  205.             if (!cleanSomeSlots(i, sz) && sz >= threshold)  
  206.                 rehash();  
  207.         }  
  208.   
  209.         private void remove(ThreadLocal key) {  
  210.             Entry[] tab = table;  
  211.             int len = tab.length;  
  212.             int i = key.threadLocalHashCode & (len-1);  
  213.             for (Entry e = tab[i];  
  214.                  e != null;  
  215.                  e = tab[i = nextIndex(i, len)]) {  
  216.                 if (e.get() == key) {  
  217.                     e.clear();  
  218.                     expungeStaleEntry(i);  
  219.                     return;  
  220.                 }  
  221.             }  
  222.         }  
  223.   
  224.         private void replaceStaleEntry(ThreadLocal key, Object value,  
  225.                                        int staleSlot) {  
  226.             Entry[] tab = table;  
  227.             int len = tab.length;  
  228.             Entry e;  
  229.   
  230.             // Back up to check for prior stale entry in current run.  
  231.             // We clean out whole runs at a time to avoid continual  
  232.             // incremental rehashing due to garbage collector freeing  
  233.             // up refs in bunches (i.e., whenever the collector runs).  
  234.             int slotToExpunge = staleSlot;  
  235.             for (int i = prevIndex(staleSlot, len);  
  236.                  (e = tab[i]) != null;  
  237.                  i = prevIndex(i, len))  
  238.                 if (e.get() == null)  
  239.                     slotToExpunge = i;  
  240.   
  241.             // Find either the key or trailing null slot of run, whichever  
  242.             // occurs first  
  243.             for (int i = nextIndex(staleSlot, len);  
  244.                  (e = tab[i]) != null;  
  245.                  i = nextIndex(i, len)) {  
  246.                 ThreadLocal k = e.get();  
  247.   
  248.                 // If we find key, then we need to swap it  
  249.                 // with the stale entry to maintain hash table order.  
  250.                 // The newly stale slot, or any other stale slot  
  251.                 // encountered above it, can then be sent to expungeStaleEntry  
  252.                 // to remove or rehash all of the other entries in run.  
  253.                 if (k == key) {  
  254.                     e.value = value;  
  255.   
  256.                     tab[i] = tab[staleSlot];  
  257.                     tab[staleSlot] = e;  
  258.   
  259.                     // Start expunge at preceding stale entry if it exists  
  260.                     if (slotToExpunge == staleSlot)  
  261.                         slotToExpunge = i;  
  262.                     cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);  
  263.                     return;  
  264.                 }  
  265.   
  266.                 // If we didn't find stale entry on backward scan, the  
  267.                 // first stale entry seen while scanning for key is the  
  268.                 // first still present in the run.  
  269.                 if (k == null && slotToExpunge == staleSlot)  
  270.                     slotToExpunge = i;  
  271.             }  
  272.   
  273.             // If key not found, put new entry in stale slot  
  274.             tab[staleSlot].value = null;  
  275.             tab[staleSlot] = new Entry(key, value);  
  276.   
  277.             // If there are any other stale entries in run, expunge them  
  278.             if (slotToExpunge != staleSlot)  
  279.                 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);  
  280.         }  
  281.   
  282.   
  283.         private int expungeStaleEntry(int staleSlot) {  
  284.             Entry[] tab = table;  
  285.             int len = tab.length;  
  286.   
  287.             // expunge entry at staleSlot  
  288.             tab[staleSlot].value = null;  
  289.             tab[staleSlot] = null;  
  290.             size--;  
  291.   
  292.             // Rehash until we encounter null  
  293.             Entry e;  
  294.             int i;  
  295.             for (i = nextIndex(staleSlot, len);  
  296.                  (e = tab[i]) != null;  
  297.                  i = nextIndex(i, len)) {  
  298.                 ThreadLocal k = e.get();  
  299.                 if (k == null) {  
  300.                     e.value = null;  
  301.                     tab[i] = null;  
  302.                     size--;  
  303.                 } else {  
  304.                     int h = k.threadLocalHashCode & (len - 1);  
  305.                     if (h != i) {  
  306.                         tab[i] = null;  
  307.   
  308.                         // Unlike Knuth 6.4 Algorithm R, we must scan until  
  309.                         // null because multiple entries could have been stale.  
  310.                         while (tab[h] != null)  
  311.                             h = nextIndex(h, len);  
  312.                         tab[h] = e;  
  313.                     }  
  314.                 }  
  315.             }  
  316.             return i;  
  317.         }  
  318.   
  319.         private boolean cleanSomeSlots(int i, int n) {  
  320.             boolean removed = false;  
  321.             Entry[] tab = table;  
  322.             int len = tab.length;  
  323.             do {  
  324.                 i = nextIndex(i, len);  
  325.                 Entry e = tab[i];  
  326.                 if (e != null && e.get() == null) {  
  327.                     n = len;  
  328.                     removed = true;  
  329.                     i = expungeStaleEntry(i);  
  330.                 }  
  331.             } while ( (n >>>= 1) != 0);  
  332.             return removed;  
  333.         }  
  334.   
  335.         private void rehash() {  
  336.             expungeStaleEntries();  
  337.   
  338.             // Use lower threshold for doubling to avoid hysteresis  
  339.             if (size >= threshold - threshold / 4)  
  340.                 resize();  
  341.         }  
  342.   
  343.         private void resize() {  
  344.             Entry[] oldTab = table;  
  345.             int oldLen = oldTab.length;  
  346.             int newLen = oldLen * 2;  
  347.             Entry[] newTab = new Entry[newLen];  
  348.             int count = 0;  
  349.   
  350.             for (int j = 0; j < oldLen; ++j) {  
  351.                 Entry e = oldTab[j];  
  352.                 if (e != null) {  
  353.                     ThreadLocal k = e.get();  
  354.                     if (k == null) {  
  355.                         e.value = null// Help the GC  
  356.                     } else {  
  357.                         int h = k.threadLocalHashCode & (newLen - 1);  
  358.                         while (newTab[h] != null)  
  359.                             h = nextIndex(h, newLen);  
  360.                         newTab[h] = e;  
  361.                         count++;  
  362.                     }  
  363.                 }  
  364.             }  
  365.   
  366.             setThreshold(newLen);  
  367.             size = count;  
  368.             table = newTab;  
  369.         }  
  370.   
  371.         private void expungeStaleEntries() {  
  372.             Entry[] tab = table;  
  373.             int len = tab.length;  
  374.             for (int j = 0; j < len; j++) {  
  375.                 Entry e = tab[j];  
  376.                 if (e != null && e.get() == null)  
  377.                     expungeStaleEntry(j);  
  378.             }  
  379.         }  
  380.     }  
  381. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值