src/share/classes/java/lang/ThreadLocal.java

Print this page
rev 6190 : [mq]: threadlocal

@@ -23,23 +23,25 @@
  * questions.
  */
 
 package java.lang;
 import java.lang.ref.*;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
 
 /**
  * This class provides thread-local variables.  These variables differ from
  * their normal counterparts in that each thread that accesses one (via its
- * <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized
- * copy of the variable.  <tt>ThreadLocal</tt> instances are typically private
+ * {@code get} or {@code set} method) has its own, independently initialized
+ * copy of the variable.  {@code ThreadLocal} instances are typically private
  * static fields in classes that wish to associate state with a thread (e.g.,
  * a user ID or Transaction ID).
  *
  * <p>For example, the class below generates unique identifiers local to each
  * thread.
- * A thread's id is assigned the first time it invokes <tt>ThreadId.get()</tt>
+ * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
  * and remains unchanged on subsequent calls.
  * <pre>
  * import java.util.concurrent.atomic.AtomicInteger;
  *
  * public class ThreadId {

@@ -59,15 +61,24 @@
  *         return threadId.get();
  *     }
  * }
  * </pre>
  * <p>Each thread holds an implicit reference to its copy of a thread-local
- * variable as long as the thread is alive and the <tt>ThreadLocal</tt>
+ * variable as long as the thread is alive and the {@code ThreadLocal}
  * instance is accessible; after a thread goes away, all of its copies of
  * thread-local instances are subject to garbage collection (unless other
  * references to these copies exist).
  *
+ * The initial value of the variable is set by (1) calling the
+ * {@code initialValue method}, (2) obtaining it from  a {@code Supplier<T>}
+ * which has been provided via the
+ * constructor, or (3) by calling the {@code set} method.
+ *
+ * If (1) is used and an initial value other than the default of null is required,
+ * the {@code initialValue} method is typically overridden with an
+ * anonymous-inner class.
+ *
  * @author  Josh Bloch and Doug Lea
  * @since   1.2
  */
 public class ThreadLocal<T> {
     /**

@@ -95,42 +106,57 @@
      * multiplicative hash values for power-of-two-sized tables.
      */
     private static final int HASH_INCREMENT = 0x61c88647;
 
     /**
+     * Supplied by the invoker of the constructor to set the initial value
+     */
+    private final Supplier<T> supplier;
+
+    /**
      * Returns the next hash code.
      */
     private static int nextHashCode() {
         return nextHashCode.getAndAdd(HASH_INCREMENT);
     }
 
     /**
      * Returns the current thread's "initial value" for this
-     * thread-local variable.  This method will be invoked the first
+     * thread-local variable unless a {@code Supplier<T>} has been passed
+     * to the constructor, in which case the Supplier is consulted in
+     * preference to this method.  This method will be invoked the first
      * time a thread accesses the variable with the {@link #get}
      * method, unless the thread previously invoked the {@link #set}
-     * method, in which case the <tt>initialValue</tt> method will not
+     * method, in which case the {@code initialValue} method will not
      * be invoked for the thread.  Normally, this method is invoked at
      * most once per thread, but it may be invoked again in case of
      * subsequent invocations of {@link #remove} followed by {@link #get}.
      *
-     * <p>This implementation simply returns <tt>null</tt>; if the
-     * programmer desires thread-local variables to have an initial
-     * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
-     * subclassed, and this method overridden.  Typically, an
-     * anonymous inner class will be used.
+     * <p>This implementation simply returns {@code null}
      *
      * @return the initial value for this thread-local
      */
     protected T initialValue() {
         return null;
     }
 
     /**
-     * Creates a thread local variable.
+     * Creates a thread local variable. The initial value of the variable is
+     * provided by calling the {@code intialValue} method.
      */
     public ThreadLocal() {
+      supplier = null;
+    }
+
+    /**
+     * Creates a thread local variable. The initial value of the variable is
+     * determined by invoking the {@code get} method on the supplier.
+     *
+     * @param supplier the supplier to be used to determine the initial value
+     */
+    public ThreadLocal(Supplier<T> supplier) {
+        this.supplier = Objects.requireNonNull(supplier);
     }
 
     /**
      * Returns the value in the current thread's copy of this
      * thread-local variable.  If the variable has no value for the

@@ -158,11 +184,11 @@
      * of set() in case user has overridden the set() method.
      *
      * @return the initial value
      */
     private T setInitialValue() {
-        T value = initialValue();
+        T value = (supplier != null ? supplier.get() : initialValue());
         Thread t = Thread.currentThread();
         ThreadLocalMap map = getMap(t);
         if (map != null)
             map.set(this, value);
         else

@@ -193,11 +219,11 @@
      * variable.  If this thread-local variable is subsequently
      * {@linkplain #get read} by the current thread, its value will be
      * reinitialized by invoking its {@link #initialValue} method,
      * unless its value is {@linkplain #set set} by the current thread
      * in the interim.  This may result in multiple invocations of the
-     * <tt>initialValue</tt> method in the current thread.
+     * {@code initialValue} method in the current thread.
      *
      * @since 1.5
      */
      public void remove() {
          ThreadLocalMap m = getMap(Thread.currentThread());

@@ -597,13 +623,13 @@
          * garbage but would cause some insertions to take O(n) time.
          *
          * @param i a position known NOT to hold a stale entry. The
          * scan starts at the element after i.
          *
-         * @param n scan control: <tt>log2(n)</tt> cells are scanned,
+         * @param n scan control: {@code log2(n)} cells are scanned,
          * unless a stale entry is found, in which case
-         * <tt>log2(table.length)-1</tt> additional cells are scanned.
+         * {@code log2(table.length)-1} additional cells are scanned.
          * When called from insertions, this parameter is the number
          * of elements, but when from replaceStaleEntry, it is the
          * table length. (Note: all this could be changed to be either
          * more or less aggressive by weighting n instead of just
          * using straight log n. But this version is simple, fast, and