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

Print this page
rev 6190 : [mq]: threadlocal

*** 23,45 **** * questions. */ package java.lang; import java.lang.ref.*; import java.util.concurrent.atomic.AtomicInteger; /** * 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 * 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> * and remains unchanged on subsequent calls. * <pre> * import java.util.concurrent.atomic.AtomicInteger; * * public class ThreadId { --- 23,47 ---- * 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 ! * {@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 {@code ThreadId.get()} * and remains unchanged on subsequent calls. * <pre> * import java.util.concurrent.atomic.AtomicInteger; * * public class ThreadId {
*** 59,73 **** * 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> * 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). * * @author Josh Bloch and Doug Lea * @since 1.2 */ public class ThreadLocal<T> { /** --- 61,84 ---- * 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 {@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,136 **** * multiplicative hash values for power-of-two-sized tables. */ private static final int HASH_INCREMENT = 0x61c88647; /** * 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 * 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 * 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. * * @return the initial value for this thread-local */ protected T initialValue() { return null; } /** ! * Creates a thread local variable. */ public ThreadLocal() { } /** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the --- 106,162 ---- * 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 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 {@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 {@code null} * * @return the initial value for this thread-local */ protected T initialValue() { return null; } /** ! * 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,168 **** * of set() in case user has overridden the set() method. * * @return the initial value */ private T setInitialValue() { ! T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else --- 184,194 ---- * of set() in case user has overridden the set() method. * * @return the initial value */ private T setInitialValue() { ! T value = (supplier != null ? supplier.get() : initialValue()); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else
*** 193,203 **** * 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. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); --- 219,229 ---- * 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 ! * {@code initialValue} method in the current thread. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread());
*** 597,609 **** * 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, * unless a stale entry is found, in which case ! * <tt>log2(table.length)-1</tt> 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 --- 623,635 ---- * 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: {@code log2(n)} cells are scanned, * unless a stale entry is found, in which case ! * {@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