zoukankan      html  css  js  c++  java
  • JDK源码解析之ThreadLocal类

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


    [java] view plaincopy
    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. }  

  • 相关阅读:
    21班考试总结
    性别
    2019.08.20上课笔记2
    2019.08.20上课笔记3
    2019.08.20上课笔记1
    单词2
    数据类和运算符
    2019.08.14单词1
    2019.08.14上课笔记1
    request.get... getHeader 能取得的信息 参数
  • 原文地址:https://www.cnblogs.com/leeeee/p/7276049.html
Copyright © 2011-2022 走看看