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

Print this page
rev 6191 : [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,69 **** * 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 --- 61,71 ---- * 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). * * @author Josh Bloch and Doug Lea
*** 106,134 **** /** * 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() { } /** --- 108,149 ---- /** * 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 {@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}; if the * programmer desires thread-local variables to have an initial ! * value other than {@code null}, {@code ThreadLocal} 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. The initial value of the variable is + * determined by invoking the {@code get} method on the {@code Supplier}. + * + * @param supplier the supplier to be used to determine the initial value + * @return a new thread local variable + * @since 1.8 + */ + public static <T> ThreadLocal<T> withInitial(Supplier<? extends T> supplier) { + return new SuppliedThreadLocal<>(supplier); + } + + /** * Creates a thread local variable. + * @see #withInitial(java.util.function.Supplier) */ public ThreadLocal() { } /**
*** 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()); --- 208,218 ---- * 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());
*** 249,258 **** --- 264,291 ---- T childValue(T parentValue) { throw new UnsupportedOperationException(); } /** + * An extension of ThreadLocal that obtains its initial value from + * the specified {@code Supplier}. + */ + static final class SuppliedThreadLocal<T> extends ThreadLocal<T> { + + private final Supplier<? extends T> supplier; + + SuppliedThreadLocal(Supplier<? extends T> supplier) { + this.supplier = Objects.requireNonNull(supplier); + } + + @Override + protected T initialValue() { + return supplier.get(); + } + } + + /** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use
*** 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 --- 630,642 ---- * 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