12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang;
27
28 import java.lang.ref.WeakReference;
29 import java.util.Objects;
30 import java.util.concurrent.atomic.AtomicInteger;
31 import java.util.function.Supplier;
32
33 import jdk.internal.misc.CarrierThreadLocal;
34 import jdk.internal.misc.TerminatingThreadLocal;
35
36 /**
37 * This class provides thread-local variables. These variables differ from
38 * their normal counterparts in that each thread that accesses one (via its
39 * {@code get} or {@code set} method) has its own, independently initialized
40 * copy of the variable. {@code ThreadLocal} instances are typically private
41 * static fields in classes that wish to associate state with a thread (e.g.,
42 * a user ID or Transaction ID).
43 *
44 * <p>For example, the class below generates unique identifiers local to each
45 * thread.
46 * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
47 * and remains unchanged on subsequent calls.
48 * <pre>
49 * import java.util.concurrent.atomic.AtomicInteger;
50 *
51 * public class ThreadId {
52 * // Atomic integer containing the next thread ID to be assigned
53 * private static final AtomicInteger nextId = new AtomicInteger(0);
54 *
60 * }
61 * };
62 *
63 * // Returns the current thread's unique ID, assigning it if necessary
64 * public static int get() {
65 * return threadId.get();
66 * }
67 * }
68 * </pre>
69 * <p>Each thread holds an implicit reference to its copy of a thread-local
70 * variable as long as the thread is alive and the {@code ThreadLocal}
71 * instance is accessible; after a thread goes away, all of its copies of
72 * thread-local instances are subject to garbage collection (unless other
73 * references to these copies exist).
74 * @param <T> the type of the thread local's value
75 *
76 * @author Josh Bloch and Doug Lea
77 * @since 1.2
78 */
79 public class ThreadLocal<T> {
80 /**
81 * ThreadLocals rely on per-thread linear-probe hash maps attached
82 * to each thread (Thread.threadLocals and
83 * inheritableThreadLocals). The ThreadLocal objects act as keys,
84 * searched via threadLocalHashCode. This is a custom hash code
85 * (useful only within ThreadLocalMaps) that eliminates collisions
86 * in the common case where consecutively constructed ThreadLocals
87 * are used by the same threads, while remaining well-behaved in
88 * less common cases.
89 */
90 private final int threadLocalHashCode = nextHashCode();
91
92 /**
93 * The next hash code to be given out. Updated atomically. Starts at
94 * zero.
95 */
96 private static AtomicInteger nextHashCode =
97 new AtomicInteger();
98
99 /**
144 * @return a new thread local variable
145 * @throws NullPointerException if the specified supplier is null
146 * @since 1.8
147 */
148 public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
149 return new SuppliedThreadLocal<>(supplier);
150 }
151
152 /**
153 * Creates a thread local variable.
154 * @see #withInitial(java.util.function.Supplier)
155 */
156 public ThreadLocal() {
157 }
158
159 /**
160 * Returns the value in the current thread's copy of this
161 * thread-local variable. If the variable has no value for the
162 * current thread, it is first initialized to the value returned
163 * by an invocation of the {@link #initialValue} method.
164 * If the current thread does not support thread locals then
165 * this method returns its {@link #initialValue}.
166 *
167 * @return the current thread's value of this thread-local
168 * @see Thread.Builder#allowSetThreadLocals(boolean)
169 */
170 public T get() {
171 return get(Thread.currentThread());
172 }
173
174 /**
175 * Returns the value in the current carrier thread's copy of this
176 * thread-local variable.
177 */
178 T getCarrierThreadLocal() {
179 assert this instanceof CarrierThreadLocal<T>;
180 return get(Thread.currentCarrierThread());
181 }
182
183 private T get(Thread t) {
184 ThreadLocalMap map = getMap(t);
185 if (map != null) {
186 if (map == ThreadLocalMap.NOT_SUPPORTED) {
187 return initialValue();
188 } else {
189 ThreadLocalMap.Entry e = map.getEntry(this);
190 if (e != null) {
191 @SuppressWarnings("unchecked")
192 T result = (T) e.value;
193 return result;
194 }
195 }
196 }
197 return setInitialValue(t);
198 }
199
200 /**
201 * Returns {@code true} if there is a value in the current carrier thread's copy of
202 * this thread-local variable, even if that values is {@code null}.
203 *
204 * @return {@code true} if current carrier thread has associated value in this
205 * thread-local variable; {@code false} if not
206 */
207 boolean isCarrierThreadLocalPresent() {
208 assert this instanceof CarrierThreadLocal<T>;
209 return isPresent(Thread.currentCarrierThread());
210 }
211
212 private boolean isPresent(Thread t) {
213 ThreadLocalMap map = getMap(t);
214 if (map != null && map != ThreadLocalMap.NOT_SUPPORTED) {
215 return map.getEntry(this) != null;
216 } else {
217 return false;
218 }
219 }
220
221 /**
222 * Variant of set() to establish initialValue. Used instead
223 * of set() in case user has overridden the set() method.
224 *
225 * @return the initial value
226 */
227 private T setInitialValue(Thread t) {
228 T value = initialValue();
229 ThreadLocalMap map = getMap(t);
230 assert map != ThreadLocalMap.NOT_SUPPORTED;
231 if (map != null) {
232 map.set(this, value);
233 } else {
234 createMap(t, value);
235 }
236 if (this instanceof TerminatingThreadLocal<?> ttl) {
237 TerminatingThreadLocal.register(ttl);
238 }
239 return value;
240 }
241
242 /**
243 * Sets the current thread's copy of this thread-local variable
244 * to the specified value. Most subclasses will have no need to
245 * override this method, relying solely on the {@link #initialValue}
246 * method to set the values of thread-locals.
247 *
248 * @param value the value to be stored in the current thread's copy of
249 * this thread-local.
250 *
251 * @throws UnsupportedOperationException if the current thread is not
252 * allowed to set its copy of thread-local variables
253 *
254 * @see Thread.Builder#allowSetThreadLocals(boolean)
255 */
256 public void set(T value) {
257 set(Thread.currentThread(), value);
258 }
259
260 void setCarrierThreadLocal(T value) {
261 assert this instanceof CarrierThreadLocal<T>;
262 set(Thread.currentCarrierThread(), value);
263 }
264
265 private void set(Thread t, T value) {
266 ThreadLocalMap map = getMap(t);
267 if (map == ThreadLocalMap.NOT_SUPPORTED) {
268 throw new UnsupportedOperationException();
269 }
270 if (map != null) {
271 map.set(this, value);
272 } else {
273 createMap(t, value);
274 }
275 }
276
277 /**
278 * Removes the current thread's value for this thread-local
279 * variable. If this thread-local variable is subsequently
280 * {@linkplain #get read} by the current thread, its value will be
281 * reinitialized by invoking its {@link #initialValue} method,
282 * unless its value is {@linkplain #set set} by the current thread
283 * in the interim. This may result in multiple invocations of the
284 * {@code initialValue} method in the current thread.
285 *
286 * @since 1.5
287 */
288 public void remove() {
289 remove(Thread.currentThread());
290 }
291
292 void removeCarrierThreadLocal() {
293 assert this instanceof CarrierThreadLocal<T>;
294 remove(Thread.currentCarrierThread());
295 }
296
297 private void remove(Thread t) {
298 ThreadLocalMap m = getMap(t);
299 if (m != null && m != ThreadLocalMap.NOT_SUPPORTED) {
300 m.remove(this);
301 }
302 }
303
304 /**
305 * Get the map associated with a ThreadLocal. Overridden in
306 * InheritableThreadLocal.
307 *
308 * @param t the current thread
309 * @return the map
310 */
311 ThreadLocalMap getMap(Thread t) {
312 return t.threadLocals;
313 }
314
315 /**
316 * Create the map associated with a ThreadLocal. Overridden in
317 * InheritableThreadLocal.
318 *
319 * @param t the current thread
377 static class ThreadLocalMap {
378
379 /**
380 * The entries in this hash map extend WeakReference, using
381 * its main ref field as the key (which is always a
382 * ThreadLocal object). Note that null keys (i.e. entry.get()
383 * == null) mean that the key is no longer referenced, so the
384 * entry can be expunged from table. Such entries are referred to
385 * as "stale entries" in the code that follows.
386 */
387 static class Entry extends WeakReference<ThreadLocal<?>> {
388 /** The value associated with this ThreadLocal. */
389 Object value;
390
391 Entry(ThreadLocal<?> k, Object v) {
392 super(k);
393 value = v;
394 }
395 }
396
397 // Placeholder when thread locals not supported
398 static final ThreadLocalMap NOT_SUPPORTED = new ThreadLocalMap();
399
400 /**
401 * The initial capacity -- MUST be a power of two.
402 */
403 private static final int INITIAL_CAPACITY = 16;
404
405 /**
406 * The table, resized as necessary.
407 * table.length MUST always be a power of two.
408 */
409 private Entry[] table;
410
411 /**
412 * The number of entries in the table.
413 */
414 private int size = 0;
415
416 /**
417 * The next size value at which to resize.
418 */
419 private int threshold; // Default to 0
790 }
791
792 setThreshold(newLen);
793 size = count;
794 table = newTab;
795 }
796
797 /**
798 * Expunge all stale entries in the table.
799 */
800 private void expungeStaleEntries() {
801 Entry[] tab = table;
802 int len = tab.length;
803 for (int j = 0; j < len; j++) {
804 Entry e = tab[j];
805 if (e != null && e.refersTo(null))
806 expungeStaleEntry(j);
807 }
808 }
809 }
810 }
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang;
27
28 import java.lang.ref.WeakReference;
29 import java.util.Objects;
30 import java.util.concurrent.atomic.AtomicInteger;
31 import java.util.function.Supplier;
32 import java.util.stream.Collectors;
33
34 import jdk.internal.misc.CarrierThreadLocal;
35 import jdk.internal.misc.TerminatingThreadLocal;
36 import sun.security.action.GetPropertyAction;
37
38 /**
39 * This class provides thread-local variables. These variables differ from
40 * their normal counterparts in that each thread that accesses one (via its
41 * {@code get} or {@code set} method) has its own, independently initialized
42 * copy of the variable. {@code ThreadLocal} instances are typically private
43 * static fields in classes that wish to associate state with a thread (e.g.,
44 * a user ID or Transaction ID).
45 *
46 * <p>For example, the class below generates unique identifiers local to each
47 * thread.
48 * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
49 * and remains unchanged on subsequent calls.
50 * <pre>
51 * import java.util.concurrent.atomic.AtomicInteger;
52 *
53 * public class ThreadId {
54 * // Atomic integer containing the next thread ID to be assigned
55 * private static final AtomicInteger nextId = new AtomicInteger(0);
56 *
62 * }
63 * };
64 *
65 * // Returns the current thread's unique ID, assigning it if necessary
66 * public static int get() {
67 * return threadId.get();
68 * }
69 * }
70 * </pre>
71 * <p>Each thread holds an implicit reference to its copy of a thread-local
72 * variable as long as the thread is alive and the {@code ThreadLocal}
73 * instance is accessible; after a thread goes away, all of its copies of
74 * thread-local instances are subject to garbage collection (unless other
75 * references to these copies exist).
76 * @param <T> the type of the thread local's value
77 *
78 * @author Josh Bloch and Doug Lea
79 * @since 1.2
80 */
81 public class ThreadLocal<T> {
82 private static final boolean TRACE_VTHREAD_LOCALS = traceVirtualThreadLocals();
83
84 /**
85 * ThreadLocals rely on per-thread linear-probe hash maps attached
86 * to each thread (Thread.threadLocals and
87 * inheritableThreadLocals). The ThreadLocal objects act as keys,
88 * searched via threadLocalHashCode. This is a custom hash code
89 * (useful only within ThreadLocalMaps) that eliminates collisions
90 * in the common case where consecutively constructed ThreadLocals
91 * are used by the same threads, while remaining well-behaved in
92 * less common cases.
93 */
94 private final int threadLocalHashCode = nextHashCode();
95
96 /**
97 * The next hash code to be given out. Updated atomically. Starts at
98 * zero.
99 */
100 private static AtomicInteger nextHashCode =
101 new AtomicInteger();
102
103 /**
148 * @return a new thread local variable
149 * @throws NullPointerException if the specified supplier is null
150 * @since 1.8
151 */
152 public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
153 return new SuppliedThreadLocal<>(supplier);
154 }
155
156 /**
157 * Creates a thread local variable.
158 * @see #withInitial(java.util.function.Supplier)
159 */
160 public ThreadLocal() {
161 }
162
163 /**
164 * Returns the value in the current thread's copy of this
165 * thread-local variable. If the variable has no value for the
166 * current thread, it is first initialized to the value returned
167 * by an invocation of the {@link #initialValue} method.
168 *
169 * @return the current thread's value of this thread-local
170 */
171 public T get() {
172 return get(Thread.currentThread());
173 }
174
175 /**
176 * Returns the value in the current carrier thread's copy of this
177 * thread-local variable.
178 */
179 T getCarrierThreadLocal() {
180 assert this instanceof CarrierThreadLocal<T>;
181 return get(Thread.currentCarrierThread());
182 }
183
184 private T get(Thread t) {
185 ThreadLocalMap map = getMap(t);
186 if (map != null) {
187 ThreadLocalMap.Entry e = map.getEntry(this);
188 if (e != null) {
189 @SuppressWarnings("unchecked")
190 T result = (T) e.value;
191 return result;
192 }
193 }
194 return setInitialValue(t);
195 }
196
197 /**
198 * Returns {@code true} if there is a value in the current carrier thread's copy of
199 * this thread-local variable, even if that values is {@code null}.
200 *
201 * @return {@code true} if current carrier thread has associated value in this
202 * thread-local variable; {@code false} if not
203 */
204 boolean isCarrierThreadLocalPresent() {
205 assert this instanceof CarrierThreadLocal<T>;
206 return isPresent(Thread.currentCarrierThread());
207 }
208
209 private boolean isPresent(Thread t) {
210 ThreadLocalMap map = getMap(t);
211 if (map != null) {
212 return map.getEntry(this) != null;
213 } else {
214 return false;
215 }
216 }
217
218 /**
219 * Variant of set() to establish initialValue. Used instead
220 * of set() in case user has overridden the set() method.
221 *
222 * @return the initial value
223 */
224 private T setInitialValue(Thread t) {
225 T value = initialValue();
226 ThreadLocalMap map = getMap(t);
227 if (map != null) {
228 map.set(this, value);
229 } else {
230 createMap(t, value);
231 }
232 if (this instanceof TerminatingThreadLocal<?> ttl) {
233 TerminatingThreadLocal.register(ttl);
234 }
235 if (TRACE_VTHREAD_LOCALS) {
236 dumpStackIfVirtualThread();
237 }
238 return value;
239 }
240
241 /**
242 * Sets the current thread's copy of this thread-local variable
243 * to the specified value. Most subclasses will have no need to
244 * override this method, relying solely on the {@link #initialValue}
245 * method to set the values of thread-locals.
246 *
247 * @param value the value to be stored in the current thread's copy of
248 * this thread-local.
249 */
250 public void set(T value) {
251 set(Thread.currentThread(), value);
252 if (TRACE_VTHREAD_LOCALS) {
253 dumpStackIfVirtualThread();
254 }
255 }
256
257 void setCarrierThreadLocal(T value) {
258 assert this instanceof CarrierThreadLocal<T>;
259 set(Thread.currentCarrierThread(), value);
260 }
261
262 private void set(Thread t, T value) {
263 ThreadLocalMap map = getMap(t);
264 if (map != null) {
265 map.set(this, value);
266 } else {
267 createMap(t, value);
268 }
269 }
270
271 /**
272 * Removes the current thread's value for this thread-local
273 * variable. If this thread-local variable is subsequently
274 * {@linkplain #get read} by the current thread, its value will be
275 * reinitialized by invoking its {@link #initialValue} method,
276 * unless its value is {@linkplain #set set} by the current thread
277 * in the interim. This may result in multiple invocations of the
278 * {@code initialValue} method in the current thread.
279 *
280 * @since 1.5
281 */
282 public void remove() {
283 remove(Thread.currentThread());
284 }
285
286 void removeCarrierThreadLocal() {
287 assert this instanceof CarrierThreadLocal<T>;
288 remove(Thread.currentCarrierThread());
289 }
290
291 private void remove(Thread t) {
292 ThreadLocalMap m = getMap(t);
293 if (m != null) {
294 m.remove(this);
295 }
296 }
297
298 /**
299 * Get the map associated with a ThreadLocal. Overridden in
300 * InheritableThreadLocal.
301 *
302 * @param t the current thread
303 * @return the map
304 */
305 ThreadLocalMap getMap(Thread t) {
306 return t.threadLocals;
307 }
308
309 /**
310 * Create the map associated with a ThreadLocal. Overridden in
311 * InheritableThreadLocal.
312 *
313 * @param t the current thread
371 static class ThreadLocalMap {
372
373 /**
374 * The entries in this hash map extend WeakReference, using
375 * its main ref field as the key (which is always a
376 * ThreadLocal object). Note that null keys (i.e. entry.get()
377 * == null) mean that the key is no longer referenced, so the
378 * entry can be expunged from table. Such entries are referred to
379 * as "stale entries" in the code that follows.
380 */
381 static class Entry extends WeakReference<ThreadLocal<?>> {
382 /** The value associated with this ThreadLocal. */
383 Object value;
384
385 Entry(ThreadLocal<?> k, Object v) {
386 super(k);
387 value = v;
388 }
389 }
390
391 /**
392 * The initial capacity -- MUST be a power of two.
393 */
394 private static final int INITIAL_CAPACITY = 16;
395
396 /**
397 * The table, resized as necessary.
398 * table.length MUST always be a power of two.
399 */
400 private Entry[] table;
401
402 /**
403 * The number of entries in the table.
404 */
405 private int size = 0;
406
407 /**
408 * The next size value at which to resize.
409 */
410 private int threshold; // Default to 0
781 }
782
783 setThreshold(newLen);
784 size = count;
785 table = newTab;
786 }
787
788 /**
789 * Expunge all stale entries in the table.
790 */
791 private void expungeStaleEntries() {
792 Entry[] tab = table;
793 int len = tab.length;
794 for (int j = 0; j < len; j++) {
795 Entry e = tab[j];
796 if (e != null && e.refersTo(null))
797 expungeStaleEntry(j);
798 }
799 }
800 }
801
802
803 /**
804 * Reads the value of the jdk.traceVirtualThreadLocals property to determine if
805 * a stack trace should be printed when a virtual threads sets a thread local.
806 */
807 private static boolean traceVirtualThreadLocals() {
808 String propValue = GetPropertyAction.privilegedGetProperty("jdk.traceVirtualThreadLocals");
809 return (propValue != null)
810 && (propValue.isEmpty() || Boolean.parseBoolean(propValue));
811 }
812
813 /**
814 * Print a stack trace if the current thread is a virtual thread.
815 */
816 static void dumpStackIfVirtualThread() {
817 if (Thread.currentThread() instanceof VirtualThread vthread) {
818 try {
819 var stack = StackWalkerHolder.STACK_WALKER.walk(s ->
820 s.skip(1) // skip caller
821 .collect(Collectors.toList()));
822
823 // switch to carrier thread to avoid recursive use of thread-locals
824 vthread.executeOnCarrierThread(() -> {
825 System.out.println(vthread);
826 for (StackWalker.StackFrame frame : stack) {
827 System.out.format(" %s%n", frame.toStackTraceElement());
828 }
829 return null;
830 });
831 } catch (Exception e) {
832 throw new InternalError(e);
833 }
834 }
835 }
836
837 private static class StackWalkerHolder {
838 static final StackWalker STACK_WALKER = StackWalker.getInstance();
839 }
840 }
|