zoukankan      html  css  js  c++  java
  • ThreadLocal源码阅读

      1 package java.lang;
      2 
      3 import java.lang.ref.WeakReference;
      4 import java.util.Objects;
      5 import java.util.concurrent.atomic.AtomicInteger;
      6 import java.util.function.Supplier;
      7 
      8 /**
      9  * This class provides thread-local variables.  These variables differ from
     10  * their normal counterparts in that each thread that accesses one (via its
     11  * {@code get} or {@code set} method) has its own, independently initialized
     12  * copy of the variable.  {@code ThreadLocal} instances are typically private
     13  * static fields in classes that wish to associate state with a thread (e.g.,
     14  * a user ID or Transaction ID).
     15  * 本类提供线程局部变量。这些变量和普通变量不同,每一个线程访问(通过get和set方法)
     16  * 的变量都是属于线程的独立初始化的一个线程局部变量的副本。线程局部变量通常是类中希望
     17  * 将状态与线程关联的私有静态域(如用户ID和事务ID)。
     18  *
     19  * <p>For example, the class below generates unique identifiers local to each
     20  * thread.
     21  * 例如,下面的类生成每个线程本地的唯一标识符。
     22  * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
     23  * and remains unchanged on subsequent calls.
     24  * 一个线程的Id在该线程首次调用get方法时生成,且在后续通话中保持不变。
     25  * <pre>
     26  * import java.util.concurrent.atomic.AtomicInteger;
     27  *
     28  * public class ThreadId {
     29  *     // Atomic integer containing the next thread ID to be assigned
     30  *     private static final AtomicInteger nextId = new AtomicInteger(0);
     31  *
     32  *     // Thread local variable containing each thread's ID
     33  *     private static final ThreadLocal<Integer> threadId =
     34  *         new ThreadLocal<Integer>() {
     35  *             @Override
     36  *             protected Integer initialValue() {
     37  *                 return nextId.getAndIncrement();
     38  *         }
     39  *     };
     40  *
     41  *     // Returns the current thread's unique ID, assigning it if necessary
     42  *     public static int get() {
     43  *         return threadId.get();
     44  *     }
     45  * }
     46  * </pre>
     47  * <p>Each thread holds an implicit reference to its copy of a thread-local
     48  * variable as long as the thread is alive and the {@code ThreadLocal}
     49  * instance is accessible; after a thread goes away, all of its copies of
     50  * thread-local instances are subject to garbage collection (unless other
     51  * references to these copies exist).
     52  * 只要线程还活着,且ThreadLocal实例能够被访问,每个线程均保留其线程局部变量
     53  * 副本的隐式引用;线程死后它的所有线程局部变量副本被垃圾回收器回收(除非存在
     54  * 对这些线程局部变量副本的其他应用)
     55  *
     56  * @author Josh Bloch and Doug Lea
     57  * @since 1.2
     58  */
     59 public class ThreadLocal<T> {
     60     /**
     61      * ThreadLocals rely on per-thread linear-probe hash maps attached
     62      * to each thread (Thread.threadLocals and inheritableThreadLocals).
     63      * ThreadLocal的实例依赖于每个线程的线性探针哈希图附加到每个线程。
     64      * The ThreadLocal objects act as keys,searched via threadLocalHashCode.
     65      * ThreadLocal对象充当键,通过threadLocalHashCode搜索。
     66      * This is a custom hash code
     67      * (useful only within ThreadLocalMaps) that eliminates collisions
     68      * in the common case where consecutively constructed ThreadLocals
     69      * are used by the same threads, while remaining well-behaved in
     70      * less common cases.
     71      * 这是一个自定义哈希码(仅在ThreadLocalMaps中有用),在相同的线程使用连续构造
     72      * 的ThreadLocals的常见情况下,它消除了冲突,而在不太常见的情况下,它们表现良好。
     73      */
     74     private final int threadLocalHashCode = nextHashCode();
     75 
     76     /**
     77      * The next hash code to be given out. Updated atomically. Starts at
     78      * zero.
     79      * 下一次给出的哈希码,该值的自动更新不能被中断(原子性),值从0开始累加。
     80      */
     81     private static AtomicInteger nextHashCode =
     82             new AtomicInteger();
     83 
     84     /**
     85      * The difference between successively generated hash codes - turns
     86      * implicit sequential thread-local IDs into near-optimally spread
     87      * multiplicative hash values for power-of-two-sized tables.
     88      * 连续生成的哈希码间的差值,
     89      */
     90     private static final int HASH_INCREMENT = 0x61c88647;
     91 
     92     /**
     93      * Returns the next hash code.
     94      * 返回下一个哈希码
     95      */
     96     private static int nextHashCode() {
     97         return nextHashCode.getAndAdd(HASH_INCREMENT);
     98     }
     99 
    100     /**
    101      * Returns the current thread's "initial value" for this
    102      * thread-local variable.  This method will be invoked the first
    103      * time a thread accesses the variable with the {@link #get}
    104      * method, unless the thread previously invoked the {@link #set}
    105      * method, in which case the {@code initialValue} method will not
    106      * be invoked for the thread.  Normally, this method is invoked at
    107      * most once per thread, but it may be invoked again in case of
    108      * subsequent invocations of {@link #remove} followed by {@link #get}.
    109      * 翻译:
    110      * 返回当前线程持有的线程局部变量副本的初始值。线程在第一次通过get方法访问局部
    111      * 变量前如果没有调用过set方法为局部变量设置值,本函数就会被调用。通常每个线程
    112      * 最多会调用一次本方法,但是如果在之后依次调用了remove和get方法,它可能会再次被调用。
    113      *
    114      * <p>This implementation simply returns {@code null}; if the
    115      * programmer desires thread-local variables to have an initial
    116      * value other than {@code null}, {@code ThreadLocal} must be
    117      * subclassed, and this method overridden.  Typically, an
    118      * anonymous inner class will be used.
    119      * 本实现仅返回null,如果开发者希望线程的局部变量具体其他初始值,只能通过声明子类并
    120      * 重写本方法。通常,将使用匿名内部类。(下面就有一个内部类)
    121      *
    122      * @return the initial value for this thread-local
    123      */
    124     protected T initialValue() {
    125         return null;
    126     }
    127 
    128     /**
    129      * Creates a thread local variable. The initial value of the variable is
    130      * determined by invoking the {@code get} method on the {@code Supplier}.
    131      * 创建一个线程局部变量的副本,变量的初始值是通过调用Supplier上的get方法确定的。
    132      * (Supplier是一个函数式接口)
    133      *
    134      * @param <S>      the type of the thread local's value
    135      * @param supplier the supplier to be used to determine the initial value
    136      * @return a new thread local variable
    137      * @throws NullPointerException if the specified supplier is null
    138      * @since 1.8
    139      */
    140     public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
    141         return new SuppliedThreadLocal<>(supplier);
    142     }
    143 
    144     /**
    145      * 构造函数
    146      * Creates a thread local variable.
    147      *
    148      * @see #withInitial(java.util.function.Supplier)
    149      */
    150     public ThreadLocal() {
    151     }
    152 
    153     /**
    154      * Returns the value in the current thread's copy of this
    155      * thread-local variable.  If the variable has no value for the
    156      * current thread, it is first initialized to the value returned
    157      * by an invocation of the {@link #initialValue} method.
    158      * 译:
    159      * 返回当前线程持有的线程局部变量副本的值。如果该变量还没赋值,
    160      * 则先使用initialValue方法为其赋予初始值。
    161      *
    162      * @return the current thread's value of this thread-local
    163      */
    164     public T get() {
    165         //1、确定当前线程
    166         Thread t = Thread.currentThread();
    167         //2、
    168         ThreadLocalMap map = getMap(t);
    169         if (map != null) {
    170             ThreadLocalMap.Entry e = map.getEntry(this);
    171             if (e != null) {
    172                 @SuppressWarnings("unchecked")
    173                 T result = (T) e.value;
    174                 return result;
    175             }
    176         }
    177         return setInitialValue();
    178     }
    179 
    180     /**
    181      * Variant of set() to establish initialValue. Used instead
    182      * of set() in case user has overridden the set() method.
    183      * 译:
    184      * set方法的变体,用于设置初始值。如果用户已覆盖set()方法,
    185      * 请使用它代替set()。
    186      *
    187      * @return the initial value
    188      */
    189     private T setInitialValue() {
    190         T value = initialValue();
    191         Thread t = Thread.currentThread();
    192         ThreadLocalMap map = getMap(t);
    193         if (map != null)
    194             map.set(this, value);
    195         else
    196             createMap(t, value);
    197         return value;
    198     }
    199 
    200     /**
    201      * Sets the current thread's copy of this thread-local variable
    202      * to the specified value.  Most subclasses will have no need to
    203      * override this method, relying solely on the {@link #initialValue}
    204      * method to set the values of thread-locals.
    205      * 译:
    206      * 设置当前线程持有的线程局部变量副本的值为指定值。大部分子类不需要重写本
    207      * 方法,仅依靠initialValue方法来设置值。
    208      *
    209      * @param value the value to be stored in the current thread's copy of
    210      *              this thread-local.
    211      */
    212     public void set(T value) {
    213         Thread t = Thread.currentThread();
    214         ThreadLocalMap map = getMap(t);
    215         if (map != null)
    216             map.set(this, value);
    217         else
    218             createMap(t, value);
    219     }
    220 
    221     /**
    222      * Removes the current thread's value for this thread-local
    223      * variable.  If this thread-local variable is subsequently
    224      * {@linkplain #get read} by the current thread, its value will be
    225      * reinitialized by invoking its {@link #initialValue} method,
    226      * unless its value is {@linkplain #set set} by the current thread
    227      * in the interim.  This may result in multiple invocations of the
    228      * {@code initialValue} method in the current thread.
    229      * 译:
    230      * 移除单前线程持有的线程本地变量的值。如果随后马上又通过get方法试图获取
    231      * 这个线程本地变量的值,这个变量的值会再次通过调用initialValue方法确定,
    232      * 除非在调用get方法前通过set方法设置了值就不会。这可能会导致initialValue
    233      * 方法被当前线程多次调用。
    234      *
    235      * @since 1.5
    236      */
    237     public void remove() {
    238         ThreadLocalMap m = getMap(Thread.currentThread());
    239         if (m != null)
    240             m.remove(this);
    241     }
    242 
    243     /**
    244      * Get the map associated with a ThreadLocal. Overridden in
    245      * InheritableThreadLocal.
    246      *
    247      * @param t the current thread
    248      * @return the map
    249      */
    250     ThreadLocalMap getMap(Thread t) {
    251         return t.threadLocals;
    252     }
    253 
    254     /**
    255      * Create the map associated with a ThreadLocal. Overridden in
    256      * InheritableThreadLocal.
    257      *
    258      * @param t          the current thread
    259      * @param firstValue value for the initial entry of the map
    260      */
    261     void createMap(Thread t, T firstValue) {
    262         t.threadLocals = new ThreadLocalMap(this, firstValue);
    263     }
    264 
    265     /**
    266      * Factory method to create map of inherited thread locals.
    267      * Designed to be called only from Thread constructor.
    268      *
    269      * @param parentMap the map associated with parent thread
    270      * @return a map containing the parent's inheritable bindings
    271      */
    272     static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
    273         return new ThreadLocalMap(parentMap);
    274     }
    275 
    276     /**
    277      * Method childValue is visibly defined in subclass
    278      * InheritableThreadLocal, but is internally defined here for the
    279      * sake of providing createInheritedMap factory method without
    280      * needing to subclass the map class in InheritableThreadLocal.
    281      * This technique is preferable to the alternative of embedding
    282      * instanceof tests in methods.
    283      */
    284     T childValue(T parentValue) {
    285         throw new UnsupportedOperationException();
    286     }
    287 
    288     /**
    289      * An extension of ThreadLocal that obtains its initial value from
    290      * the specified {@code Supplier}.
    291      * SuppliedThreadLocal类拓展了ThreadLocal类,该类重写了initialValue函数,
    292      * 用于从指定的Supplier获取初始值。
    293      */
    294     static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
    295 
    296         /**
    297          * Supplier<T>是一个函数式接口
    298          */
    299         private final Supplier<? extends T> supplier;
    300 
    301         /**
    302          * 构造函数
    303          *
    304          * @param supplier - 一个函数式接口,用来返回线程本地变量的初始值
    305          */
    306         SuppliedThreadLocal(Supplier<? extends T> supplier) {
    307             /**
    308              *     public static <T> T requireNonNull(T obj) {
    309              *         if (obj == null)
    310              *             throw new NullPointerException();
    311              *         return obj;
    312              *     }
    313              */
    314             this.supplier = Objects.requireNonNull(supplier);
    315         }
    316 
    317         /**
    318          * 这里很关键,需要去看看Supplier接口的源码。
    319          */
    320         @Override
    321         protected T initialValue() {
    322             return supplier.get();
    323         }
    324     }
    325 
    326     /**
    327      * ThreadLocalMap is a customized hash map suitable only for
    328      * maintaining thread local values. No operations are exported
    329      * outside of the ThreadLocal class. The class is package private to
    330      * allow declaration of fields in class Thread.  To help deal with
    331      * very large and long-lived usages, the hash table entries use
    332      * WeakReferences for keys. However, since reference queues are not
    333      * used, stale entries are guaranteed to be removed only when
    334      * the table starts running out of space.
    335      * 译:
    336      * ThreadLocalMap是自定义的HashMap,仅适用于维护线程局部变量的值。
    337      * 没有操作导出到ThreadLocal类之外。这个类是包私有的,用于Thread类
    338      * 域声明。为了处理存储空间消耗大,使用时间长的使用情况,这个HashTable
    339      * 使用WeakReferences(弱引用)作为键。但是,由于未使用参考队列,因此
    340      * 仅在表开始空间不足时,才保证删除过时的条目。
    341      */
    342     static class ThreadLocalMap {
    343 
    344         /**
    345          * The entries in this hash map extend WeakReference, using
    346          * its main ref field as the key (which is always a
    347          * ThreadLocal object).  Note that null keys (i.e. entry.get()
    348          * == null) mean that the key is no longer referenced, so the
    349          * entry can be expunged from table.  Such entries are referred to
    350          * as "stale entries" in the code that follows.
    351          * 译:
    352          * 该哈希表中的条目是WeakReference子类的对象,以其主域作为键(大多数情
    353          * 况下是一个ThreadLocal对象)。需要注意,当以null作为键时,意味着这个
    354          * 键已经不再被引用,因此这个键所在的条目能被表移除。这样的条目我们在下文
    355          * 中称为“过时的条目”
    356          */
    357         static class Entry extends WeakReference<ThreadLocal<?>> {
    358             /**
    359              * The value associated with this ThreadLocal.
    360              * 与ThreadLocal相关联的值
    361              */
    362             Object value;
    363 
    364             /**
    365              * @param k - 以线程作为键
    366              * @param v - 线程持有的threal-local变量副本的值
    367              */
    368             Entry(ThreadLocal<?> k, Object v) {
    369                 super(k);
    370                 value = v;
    371             }
    372         }
    373 
    374         /**
    375          * The initial capacity -- MUST be a power of two.
    376          * 初始容量——必须是2的幂
    377          */
    378         private static final int INITIAL_CAPACITY = 16;
    379 
    380         /**
    381          * The table, resized as necessary.
    382          * table.length MUST always be a power of two.
    383          * 译:
    384          * 表在必要的时候会扩容,表的大小必须是2的幂
    385          */
    386         private Entry[] table;
    387 
    388         /**
    389          * The number of entries in the table.
    390          * 表中条目(键值对)的数量
    391          */
    392         private int size = 0;
    393 
    394         /**
    395          * the next size value at which to resize.
    396          * 下一次调整表的大小时要增加的值
    397          */
    398         private int threshold; // Default to 0
    399 
    400         /**
    401          * Set the resize threshold to maintain at worst a 2/3 load factor.
    402          * 从这里可以看出,每次扩容,容量增加2/3。
    403          */
    404         private void setThreshold(int len) {
    405             threshold = len * 2 / 3;
    406         }
    407 
    408         /**
    409          * Increment i modulo len.
    410          */
    411         private static int nextIndex(int i, int len) {
    412             return ((i + 1 < len) ? i + 1 : 0);
    413         }
    414 
    415         /**
    416          * Decrement i modulo len.
    417          */
    418         private static int prevIndex(int i, int len) {
    419             return ((i - 1 >= 0) ? i - 1 : len - 1);
    420         }
    421 
    422         /**
    423          * Construct a new map initially containing (firstKey, firstValue).
    424          * ThreadLocalMaps are constructed lazily, so we only create
    425          * one when we have at least one entry to put in it.
    426          * 译:
    427          * 构造一个最初包含以下内容的新Map。ThreadLocalMaps是延迟创建的,所以
    428          * 只有当至少要添加一条条目时才创建一个。
    429          */
    430         ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    431             table = new Entry[INITIAL_CAPACITY];
    432             int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    433             table[i] = new Entry(firstKey, firstValue);
    434             size = 1;
    435             setThreshold(INITIAL_CAPACITY);
    436         }
    437 
    438         /**
    439          * Construct a new map including all Inheritable ThreadLocals
    440          * from given parent map. Called only by createInheritedMap.
    441          *
    442          * @param parentMap the map associated with parent thread.
    443          */
    444         private ThreadLocalMap(ThreadLocalMap parentMap) {
    445             Entry[] parentTable = parentMap.table;
    446             int len = parentTable.length;
    447             setThreshold(len);
    448             table = new Entry[len];
    449 
    450             for (int j = 0; j < len; j++) {
    451                 Entry e = parentTable[j];
    452                 if (e != null) {
    453                     @SuppressWarnings("unchecked")
    454                     ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
    455                     if (key != null) {
    456                         Object value = key.childValue(e.value);
    457                         Entry c = new Entry(key, value);
    458                         int h = key.threadLocalHashCode & (len - 1);
    459                         while (table[h] != null)
    460                             h = nextIndex(h, len);
    461                         table[h] = c;
    462                         size++;
    463                     }
    464                 }
    465             }
    466         }
    467 
    468         /**
    469          * Get the entry associated with key.  This method
    470          * itself handles only the fast path: a direct hit of existing
    471          * key. It otherwise relays to getEntryAfterMiss.  This is
    472          * designed to maximize performance for direct hits, in part
    473          * by making this method readily inlinable.
    474          * 译:
    475          * 获取键关联的条目。
    476          * 理解:
    477          * 散列表中通过哈希函数和键计算哈希码,使用哈希码来决定数据存储的位置,
    478          * 不同的键通过哈希函数可能计算出相同的哈希码,这被称为“冲突”。遇到冲突
    479          * 时需要使用某种“冲突解决策略”重新确定一个哈希码,本函数假设没有冲突,
    480          * 尝试通过计算出来的哈希码直接取值。事实上好的哈希算法计算出来的哈希码
    481          * 分布的比较均匀,即很少发生冲突。
    482          *
    483          * @param key the thread local object
    484          * @return the entry associated with key, or null if no such
    485          */
    486         private Entry getEntry(ThreadLocal<?> key) {
    487             //1、尝试直接取值
    488             int i = key.threadLocalHashCode & (table.length - 1);
    489             Entry e = table[i];
    490             if (e != null && e.get() == key)
    491                 return e;
    492             else
    493                 return getEntryAfterMiss(key, i, e);//2、冲突解决方案
    494         }
    495 
    496         /**
    497          * Version of getEntry method for use when key is not found in
    498          * its direct hash slot.
    499          *
    500          * @param key the thread local object
    501          * @param i   the table index for key's hash code
    502          * @param e   the entry at table[i]
    503          * @return the entry associated with key, or null if no such
    504          */
    505         private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
    506             Entry[] tab = table;
    507             int len = tab.length;
    508 
    509             while (e != null) {
    510                 ThreadLocal<?> k = e.get();
    511                 if (k == key)
    512                     return e;
    513                 if (k == null)
    514                     expungeStaleEntry(i);
    515                 else
    516                     i = nextIndex(i, len);
    517                 e = tab[i];
    518             }
    519             return null;
    520         }
    521 
    522         /**
    523          * Set the value associated with key.
    524          * 设置与键关联的值
    525          *
    526          * @param key   the thread local object
    527          * @param value the value to be set
    528          */
    529         private void set(ThreadLocal<?> key, Object value) {
    530 
    531             // We don't use a fast path as with get() because it is at
    532             // least as common to use set() to create new entries as
    533             // it is to replace existing ones, in which case, a fast
    534             // path would fail more often than not.
    535 
    536             Entry[] tab = table;
    537             int len = tab.length;
    538             int i = key.threadLocalHashCode & (len - 1);
    539 
    540             for (Entry e = tab[i];
    541                  e != null;
    542                  e = tab[i = nextIndex(i, len)]) {
    543                 ThreadLocal<?> k = e.get();
    544 
    545                 if (k == key) {
    546                     e.value = value;
    547                     return;
    548                 }
    549 
    550                 if (k == null) {
    551                     replaceStaleEntry(key, value, i);
    552                     return;
    553                 }
    554             }
    555 
    556             tab[i] = new Entry(key, value);
    557             int sz = ++size;
    558             if (!cleanSomeSlots(i, sz) && sz >= threshold)
    559                 rehash();
    560         }
    561 
    562         /**
    563          * Remove the entry for key.
    564          */
    565         private void remove(ThreadLocal<?> key) {
    566             Entry[] tab = table;
    567             int len = tab.length;
    568             int i = key.threadLocalHashCode & (len - 1);
    569             for (Entry e = tab[i];
    570                  e != null;
    571                  e = tab[i = nextIndex(i, len)]) {
    572                 if (e.get() == key) {
    573                     e.clear();
    574                     expungeStaleEntry(i);
    575                     return;
    576                 }
    577             }
    578         }
    579 
    580         /**
    581          * Replace a stale entry encountered during a set operation
    582          * with an entry for the specified key.  The value passed in
    583          * the value parameter is stored in the entry, whether or not
    584          * an entry already exists for the specified key.
    585          * <p>
    586          * As a side effect, this method expunges all stale entries in the
    587          * "run" containing the stale entry.  (A run is a sequence of entries
    588          * between two null slots.)
    589          *
    590          * @param key       the key
    591          * @param value     the value to be associated with key
    592          * @param staleSlot index of the first stale entry encountered while
    593          *                  searching for key.
    594          */
    595         private void replaceStaleEntry(ThreadLocal<?> key, Object value,
    596                                        int staleSlot) {
    597             Entry[] tab = table;
    598             int len = tab.length;
    599             Entry e;
    600 
    601             // Back up to check for prior stale entry in current run.
    602             // We clean out whole runs at a time to avoid continual
    603             // incremental rehashing due to garbage collector freeing
    604             // up refs in bunches (i.e., whenever the collector runs).
    605             int slotToExpunge = staleSlot;
    606             for (int i = prevIndex(staleSlot, len);
    607                  (e = tab[i]) != null;
    608                  i = prevIndex(i, len))
    609                 if (e.get() == null)
    610                     slotToExpunge = i;
    611 
    612             // Find either the key or trailing null slot of run, whichever
    613             // occurs first
    614             for (int i = nextIndex(staleSlot, len);
    615                  (e = tab[i]) != null;
    616                  i = nextIndex(i, len)) {
    617                 ThreadLocal<?> k = e.get();
    618 
    619                 // If we find key, then we need to swap it
    620                 // with the stale entry to maintain hash table order.
    621                 // The newly stale slot, or any other stale slot
    622                 // encountered above it, can then be sent to expungeStaleEntry
    623                 // to remove or rehash all of the other entries in run.
    624                 if (k == key) {
    625                     e.value = value;
    626 
    627                     tab[i] = tab[staleSlot];
    628                     tab[staleSlot] = e;
    629 
    630                     // Start expunge at preceding stale entry if it exists
    631                     if (slotToExpunge == staleSlot)
    632                         slotToExpunge = i;
    633                     cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
    634                     return;
    635                 }
    636 
    637                 // If we didn't find stale entry on backward scan, the
    638                 // first stale entry seen while scanning for key is the
    639                 // first still present in the run.
    640                 if (k == null && slotToExpunge == staleSlot)
    641                     slotToExpunge = i;
    642             }
    643 
    644             // If key not found, put new entry in stale slot
    645             tab[staleSlot].value = null;
    646             tab[staleSlot] = new Entry(key, value);
    647 
    648             // If there are any other stale entries in run, expunge them
    649             if (slotToExpunge != staleSlot)
    650                 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
    651         }
    652 
    653         /**
    654          * Expunge a stale entry by rehashing any possibly colliding entries
    655          * lying between staleSlot and the next null slot.  this also expunges
    656          * any other stale entries encountered before the trailing null.  See
    657          * Knuth, Section 6.4
    658          * 译:
    659          * 通过重新散列位于staleSlot和下一个null插槽之间的任何可能冲突的条目来清除
    660          * 陈旧的条目。这还将删除尾随null之前遇到的所有其他过时的条目。
    661          *
    662          * @param staleSlot index of slot known to have null key
    663          * @return the index of the next null slot after staleSlot
    664          * (all between staleSlot and this slot will have been checked
    665          * for expunging).
    666          */
    667         private int expungeStaleEntry(int staleSlot) {
    668             Entry[] tab = table;
    669             int len = tab.length;
    670 
    671             // expunge entry at staleSlot
    672             tab[staleSlot].value = null;
    673             tab[staleSlot] = null;
    674             size--;
    675 
    676             // Rehash until we encounter null
    677             Entry e;
    678             int i;
    679             for (i = nextIndex(staleSlot, len);
    680                  (e = tab[i]) != null;
    681                  i = nextIndex(i, len)) {
    682                 ThreadLocal<?> k = e.get();
    683                 if (k == null) {
    684                     e.value = null;
    685                     tab[i] = null;
    686                     size--;
    687                 } else {
    688                     int h = k.threadLocalHashCode & (len - 1);
    689                     if (h != i) {
    690                         tab[i] = null;
    691 
    692                         // Unlike Knuth 6.4 Algorithm R, we must scan until
    693                         // null because multiple entries could have been stale.
    694                         while (tab[h] != null)
    695                             h = nextIndex(h, len);
    696                         tab[h] = e;
    697                     }
    698                 }
    699             }
    700             return i;
    701         }
    702 
    703         /**
    704          * Heuristically scan some cells looking for stale entries.
    705          * This is invoked when either a new element is added, or
    706          * another stale one has been expunged. It performs a
    707          * logarithmic number of scans, as a balance between no
    708          * scanning (fast but retains garbage) and a number of scans
    709          * proportional to number of elements, that would find all
    710          * garbage but would cause some insertions to take O(n) time.
    711          * 译:
    712          * 启发式扫描某些单元以查找陈旧条目。当添加了新元素或已删除另一旧
    713          * 元素时,将调用此方法。它执行对数扫描,作为无扫描(快速但保留垃
    714          * 圾)和与元素数量成正比的扫描数量之间的平衡,这会发现所有垃圾,
    715          * 但会导致某些插入花费O(n)时间。
    716          *
    717          * @param i a position known NOT to hold a stale entry. The
    718          *          scan starts at the element after i.
    719          * @param n scan control: {@code log2(n)} cells are scanned,
    720          *          unless a stale entry is found, in which case
    721          *          {@code log2(table.length)-1} additional cells are scanned.
    722          *          When called from insertions, this parameter is the number
    723          *          of elements, but when from replaceStaleEntry, it is the
    724          *          table length. (Note: all this could be changed to be either
    725          *          more or less aggressive by weighting n instead of just
    726          *          using straight log n. But this version is simple, fast, and
    727          *          seems to work well.)
    728          * @return true if any stale entries have been removed.
    729          */
    730         private boolean cleanSomeSlots(int i, int n) {
    731             boolean removed = false;
    732             Entry[] tab = table;
    733             int len = tab.length;
    734             do {
    735                 i = nextIndex(i, len);
    736                 Entry e = tab[i];
    737                 if (e != null && e.get() == null) {
    738                     n = len;
    739                     removed = true;
    740                     i = expungeStaleEntry(i);
    741                 }
    742             } while ((n >>>= 1) != 0);
    743             return removed;
    744         }
    745 
    746         /**
    747          * Re-pack and/or re-size the table. First scan the entire
    748          * table removing stale entries. If this doesn't sufficiently
    749          * shrink the size of the table, double the table size.
    750          * 译:
    751          * 重新包装和/或调整表大小。首先扫描整个表,删除陈旧的条目。
    752          * 如果这还不足以缩小表格的大小,请将表格大小加倍。
    753          */
    754         private void rehash() {
    755             expungeStaleEntries();
    756 
    757             // Use lower threshold for doubling to avoid hysteresis
    758             if (size >= threshold - threshold / 4)
    759                 resize();
    760         }
    761 
    762         /**
    763          * Double the capacity of the table.
    764          * 使表的容积几倍。
    765          */
    766         private void resize() {
    767             Entry[] oldTab = table;
    768             int oldLen = oldTab.length;
    769             int newLen = oldLen * 2;
    770             Entry[] newTab = new Entry[newLen];
    771             int count = 0;
    772 
    773             for (int j = 0; j < oldLen; ++j) {
    774                 Entry e = oldTab[j];
    775                 if (e != null) {
    776                     ThreadLocal<?> k = e.get();
    777                     if (k == null) {
    778                         e.value = null; // Help the GC
    779                     } else {
    780                         int h = k.threadLocalHashCode & (newLen - 1);
    781                         while (newTab[h] != null)
    782                             h = nextIndex(h, newLen);
    783                         newTab[h] = e;
    784                         count++;
    785                     }
    786                 }
    787             }
    788 
    789             setThreshold(newLen);
    790             size = count;
    791             table = newTab;
    792         }
    793 
    794         /**
    795          * Expunge all stale entries in the table.
    796          * 清除表中所有过时条目
    797          */
    798         private void expungeStaleEntries() {
    799             Entry[] tab = table;
    800             int len = tab.length;
    801             for (int j = 0; j < len; j++) {
    802                 Entry e = tab[j];
    803                 if (e != null && e.get() == null)
    804                     expungeStaleEntry(j);
    805             }
    806         }
    807     }
    808 }
     1 /*
     2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     4  *
     5  *
     6  *
     7  *
     8  *
     9  *
    10  *
    11  *
    12  *
    13  *
    14  *
    15  *
    16  *
    17  *
    18  *
    19  *
    20  *
    21  *
    22  *
    23  *
    24  */
    25 package java.util.function;
    26 
    27 /**
    28  * 该类函数式接口应用于支持Lambda表达式的API中,
    29  * Supplier接口用于提供一个T类对象。
    30  */
    31 
    32 /**
    33  * Represents a supplier of results.
    34  * 代表结果的提供者
    35  *
    36  * <p>There is no requirement that a new or distinct result be returned each
    37  * time the supplier is invoked.
    38  * 并不要求每次调用都返回一个新的或者不同的结果。
    39  *
    40  * <p>This is a <a href="package-summary.html">functional interface</a>
    41  * whose functional method is {@link #get()}.
    42  *
    43  * @param <T> the type of results supplied by this supplier
    44  * @since 1.8
    45  */
    46 @FunctionalInterface
    47 public interface Supplier<T> {
    48 
    49     /**
    50      * Gets a result.
    51      *
    52      * @return a result
    53      */
    54     T get();
    55 }
  • 相关阅读:
    BZOJ 2073: [POI2004]PRZ [DP 状压]
    POJ 2404 Jogging Trails [DP 状压 一般图最小权完美匹配]
    BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】
    BZOJ 1226: [SDOI2009]学校食堂Dining [DP 状压]
    BZOJ 2734: [HNOI2012]集合选数 [DP 状压 转化]
    BZOJ 1097: [POI2007]旅游景点atr [DP 状压 最短路]
    BZOJ 1072: [SCOI2007]排列perm [DP 状压 排列组合]
    USACO 状压DP练习[3]
    CF781D Axel and Marston in Bitland [倍增 矩阵乘法 bitset]
    Codeforces Round #403 (Div. 2, based on Technocup 2017 Finals)
  • 原文地址:https://www.cnblogs.com/XiaoZhengYu/p/12047268.html
Copyright © 2011-2022 走看看