ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/java/lang/ThreadLocal.java
Revision: 1.3
Committed: Wed May 14 21:30:38 2003 UTC (21 years, 1 month ago) by tim
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +0 -0 lines
State: FILE REMOVED
Log Message:
Moved main source rooted at . to ./src/main
Moved test source rooted at ./etc/testcases to ./src/test

File Contents

# Content
1 /*
2 * @(#)ThreadLocal.java 1.19 01/12/03
3 *
4 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7
8 package java.lang;
9 import java.lang.ref.*;
10
11 /**
12 * <b>JSR166: Added remove() method</b>.<p>
13 * This class provides thread-local variables. These variables differ from
14 * their normal counterparts in that each thread that accesses one (via its
15 * <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized
16 * copy of the variable. <tt>ThreadLocal</tt> instances are typically private
17 * static fields in classes that wish to associate state with a thread (e.g.,
18 * a user ID or Transaction ID).
19 *
20 * <p>For example, in the class below, the private static <tt>ThreadLocal</tt>
21 * instance (<tt>serialNum</tt>) maintains a "serial number" for each thread
22 * that invokes the class's static <tt>SerialNum.get()</tt> method, which
23 * returns the current thread's serial number. (A thread's serial number is
24 * assigned the first time it invokes <tt>SerialNum.get()</tt>, and remains
25 * unchanged on subsequent calls.)
26 * <pre>
27 * public class SerialNum {
28 * // The next serial number to be assigned
29 * private static int nextSerialNum = 0;
30 *
31 * private static ThreadLocal serialNum = new ThreadLocal() {
32 * protected synchronized Object initialValue() {
33 * return new Integer(nextSerialNum++);
34 * }
35 * };
36 *
37 * public static int get() {
38 * return ((Integer) (serialNum.get())).intValue();
39 * }
40 * }
41 * </pre>
42 *
43 * <p>Each thread holds an implicit reference to its copy of a thread-local
44 * variable as long as the thread is alive and the <tt>ThreadLocal</tt>
45 * instance is accessible; after a thread goes away, all of its copies of
46 * thread-local instances are subject to garbage collection (unless other
47 * references to these copies exist).
48 *
49 * @author Josh Bloch and Doug Lea
50 * @version 1.19, 12/03/01
51 * @since 1.2
52 */
53 public class ThreadLocal {
54 /**
55 * ThreadLocals rely on per-thread hash maps attached to each thread
56 * (Thread.threadLocals and inheritableThreadLocals). The ThreadLocal
57 * objects act as keys, searched via threadLocalHashCode. This is a
58 * custom hash code (useful only within ThreadLocalMaps) that eliminates
59 * collisions in the common case where consecutively constructed
60 * ThreadLocals are used by the same threads, while remaining well-behaved
61 * in less common cases.
62 */
63 private final int threadLocalHashCode = nextHashCode();
64
65 /**
66 * The next hash code to be given out. Accessed only by like-named method.
67 */
68 private static int nextHashCode = 0;
69
70 /**
71 * The difference between successively generated hash codes - turns
72 * implicit sequential thread-local IDs into near-optimally spread
73 * multiplicative hash values for power-of-two-sized tables.
74 */
75 private static final int HASH_INCREMENT = 0x61c88647;
76
77 /**
78 * Compute the next hash code. The static synchronization used here
79 * should not be a performance bottleneck. When ThreadLocals are
80 * generated in different threads at a fast enough rate to regularly
81 * contend on this lock, memory contention is by far a more serious
82 * problem than lock contention.
83 */
84 private static synchronized int nextHashCode() {
85 int h = nextHashCode;
86 nextHashCode = h + HASH_INCREMENT;
87 return h;
88 }
89
90 /**
91 * Returns the current thread's initial value for this thread-local
92 * variable. This method will be called once per accessing thread for each
93 * thread-local, the first time each thread accesses the variable with the
94 * {@link #get()} or {@link #set(Object)} method. If the programmer
95 * desires thread-local variables to be initialized to some value other
96 * than <tt>null</tt>, <tt>ThreadLocal</tt> must be subclassed, and this
97 * method overridden. Typically, an anonymous inner class will be used.
98 * Typical implementations of <tt>initialValue</tt> will call an
99 * appropriate constructor and return the newly constructed object.
100 *
101 * @return the initial value for this thread-local
102 */
103 protected Object initialValue() {
104 return null;
105 }
106
107 /**
108 * Returns the value in the current thread's copy of this thread-local
109 * variable. Creates and initializes the copy if this is the first time
110 * the thread has called this method.
111 *
112 * @return the current thread's value of this thread-local
113 */
114 public Object get() {
115 Thread t = Thread.currentThread();
116 ThreadLocalMap map = getMap(t);
117 if (map != null)
118 return map.get(this);
119
120 // Maps are constructed lazily. if the map for this thread
121 // doesn't exist, create it, with this ThreadLocal and its
122 // initial value as its only entry.
123 Object value = initialValue();
124 createMap(t, value);
125 return value;
126 }
127
128 /**
129 * Sets the current thread's copy of this thread-local variable
130 * to the specified value. This is only used to change the value from
131 * the one assigned by the <tt>initialValue</tt> method, and many
132 * applications will have no need for this functionality.
133 *
134 * @param value the value to be stored in the current threads' copy of
135 * this thread-local.
136 */
137 public void set(Object value) {
138 Thread t = Thread.currentThread();
139 ThreadLocalMap map = getMap(t);
140 if (map != null)
141 map.set(this, value);
142 else
143 createMap(t, value);
144 }
145
146 /**
147 * Removes the value for this ThreadLocal. This may help reduce
148 * the storage requirements of ThreadLocals. If this ThreadLocal
149 * is accessed again, it will by default have its
150 * <tt>initialValue</tt>.
151 **/
152
153 public void remove() {
154 ThreadLocalMap m = getMap(Thread.currentThread());
155 if (m != null)
156 m.remove(this);
157 }
158
159 /**
160 * Get the map associated with a ThreadLocal. Overridden in
161 * InheritableThreadLocal.
162 *
163 * @param t the current thread
164 * @return the map
165 */
166 ThreadLocalMap getMap(Thread t) {
167 return t.threadLocals;
168 }
169
170 /**
171 * Create the map associated with a ThreadLocal. Overridden in
172 * InheritableThreadLocal.
173 *
174 * @param t the current thread
175 * @param firstValue value for the initial entry of the map
176 * @param map the map to store.
177 */
178 void createMap(Thread t, Object firstValue) {
179 t.threadLocals = new ThreadLocalMap(this, firstValue);
180 }
181
182 /**
183 * Factory method to create map of inherited thread locals.
184 * Designed to be called only from Thread constructor.
185 *
186 * @param parentMap the map associated with parent thread
187 * @return a map containing the parent's inheritable bindings
188 */
189 static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
190 return new ThreadLocalMap(parentMap);
191 }
192
193 /**
194 * Method childValue is visibly defined in subclass
195 * InheritableThreadLocal, but is internally defined here for the
196 * sake of providing createInheritedMap factory method without
197 * needing to subclass the map class in InheritableThreadLocal.
198 * This technique is preferable to the alternative of embedding
199 * instanceof tests in methods.
200 */
201 Object childValue(Object parentValue) {
202 throw new UnsupportedOperationException();
203 }
204
205 /**
206 * ThreadLocalMap is a customized hash map suitable only for
207 * maintaining thread local values. No operations are exported
208 * outside of the ThreadLocal class. The class is package private to
209 * allow declaration of fields in class Thread. To help deal with
210 * very large and long-lived usages, the hash table entries use
211 * WeakReferences for keys. However, since reference queues are not
212 * used, stale entries are guaranteed to be removed only when
213 * the table starts running out of space.
214 */
215 static class ThreadLocalMap {
216
217 /**
218 * The entries in this hash map extend WeakReference, using
219 * its main ref field as the key (which is always a
220 * ThreadLocal object). Note that null keys (i.e. entry.get()
221 * == null) mean that the key is no longer referenced, so the
222 * entry can be expunged from table. Such entries are referred to
223 * as "stale entries" in the code that follows.
224 */
225 private static class Entry extends WeakReference {
226 /** The value associated with this ThreadLocal. */
227 private Object value;
228
229 private Entry(ThreadLocal k, Object v) {
230 super(k);
231 value = v;
232 }
233 }
234
235 /**
236 * The initial capacity -- MUST be a power of two.
237 */
238 private static final int INITIAL_CAPACITY = 16;
239
240 /**
241 * The table, resized as necessary.
242 * table.length MUST always be a power of two.
243 */
244 private Entry[] table;
245
246 /**
247 * The number of entries in the table.
248 */
249 private int size = 0;
250
251 /**
252 * The next size value at which to resize.
253 */
254 private int threshold;
255
256 /**
257 * Set the resize threshold to maintain at worst a 2/3 load factor.
258 */
259 private void setThreshold(int len) {
260 threshold = len * 2 / 3;
261 }
262
263 /**
264 * Increment i modulo len.
265 */
266 private static int nextIndex(int i, int len) {
267 return ((i + 1 < len) ? i + 1 : 0);
268 }
269
270 /**
271 * Decrement i modulo len.
272 */
273 private static int prevIndex(int i, int len) {
274 return ((i - 1 >= 0) ? i - 1 : len - 1);
275 }
276
277 /**
278 * Construct a new map initially containing (firstKey, firstValue).
279 * ThreadLocalMaps are constructed lazily, so we only create
280 * one when we have at least one entry to put in it.
281 */
282 ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
283 table = new Entry[INITIAL_CAPACITY];
284 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
285 table[i] = new Entry(firstKey, firstValue);
286 size = 1;
287 setThreshold(INITIAL_CAPACITY);
288 }
289
290 /**
291 * Construct a new map including all Inheritable ThreadLocals
292 * from given parent map. Called only by createInheritedMap.
293 *
294 * @param parentMap the map associated with parent thread.
295 */
296 private ThreadLocalMap(ThreadLocalMap parentMap) {
297 Entry[] parentTable = parentMap.table;
298 int len = parentTable.length;
299 setThreshold(len);
300 table = new Entry[len];
301
302 for (int j = 0; j < len; j++) {
303 Entry e = parentTable[j];
304 if (e != null) {
305 Object k = e.get();
306 if (k != null) {
307 ThreadLocal key = (ThreadLocal)(k);
308 Object value = key.childValue(e.value);
309 Entry c = new Entry(key, value);
310 int h = key.threadLocalHashCode & (len - 1);
311 while (table[h] != null)
312 h = nextIndex(h, len);
313 table[h] = c;
314 size++;
315 }
316 }
317 }
318 }
319
320 /**
321 * Get the value associated with key with code h. This method itself
322 * handles only the fast path: a direct hit of existing key. It
323 * otherwise relays to getAfterMiss. This is designed to maximize
324 * performance for direct hits, in part by making this method readily
325 * inlinable.
326 *
327 * @param key the thread local object
328 * @param h key's hash code
329 * @return the value associated with key
330 */
331 private Object get(ThreadLocal key) {
332 int i = key.threadLocalHashCode & (table.length - 1);
333 Entry e = table[i];
334 if (e != null && e.get() == key)
335 return e.value;
336
337 return getAfterMiss(key, i, e);
338 }
339
340 /**
341 * Version of get method for use when key is not found in its
342 * direct hash slot.
343 *
344 * @param key the thread local object
345 * @param i the table index for key's hash code
346 * @param e the entry at table[i];
347 * @return the value associated with key
348 */
349 private Object getAfterMiss(ThreadLocal key, int i, Entry e) {
350 Entry[] tab = table;
351 int len = tab.length;
352
353 while (e != null) {
354 Object k = e.get();
355 if (k == key)
356 return e.value;
357 if (k == null)
358 return replaceStaleEntry(key, null, i, true);
359
360 i = nextIndex(i, len);
361 e = tab[i];
362 }
363
364 Object value = key.initialValue();
365 tab[i] = new Entry(key, value);
366 if (++size >= threshold)
367 rehash();
368
369 return value;
370 }
371
372 /**
373 * Set the value associated with key.
374 *
375 * @param key the thread local object
376 * @param value the value to be set
377 */
378 private void set(ThreadLocal key, Object value) {
379
380 // We don't use a fast path as with get() because it is at
381 // least as common to use set() to create new entries as
382 // it is to replace existing ones, in which case, a fast
383 // path would fail more often than not.
384
385 Entry[] tab = table;
386 int len = tab.length;
387 int i = key.threadLocalHashCode & (len-1);
388
389 for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
390 Object k = e.get();
391
392 if (k == key) {
393 e.value = value;
394 return;
395 }
396
397 if (k == null) {
398 replaceStaleEntry(key, value, i, false);
399 return;
400 }
401 }
402
403 tab[i] = new Entry(key, value);
404 if (++size >= threshold)
405 rehash();
406 }
407
408 /**
409 * Remove the entry for key.
410 */
411 private void remove(ThreadLocal key) {
412 Entry[] tab = table;
413 int len = tab.length;
414 int i = key.threadLocalHashCode & (len-1);
415 for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
416 if (e.get() == key) {
417 e.clear();
418 expungeStaleEntry(i);
419 return;
420 }
421 }
422 }
423
424 /**
425 * Replace a stale entry encountered during a get or set operation
426 * with an entry for the specified key. If actAsGet is true and an
427 * entry for the key already exists, the value in the entry is
428 * unchanged; if no entry exists for the key, the value in the new
429 * entry is obtained by calling key.initialValue. If actAsGet is
430 * false, the value passed in the value parameter is stored in the
431 * entry, whether or not an entry already exists for the specified key.
432 *
433 * As a side effect, this method expunges all stale entries in the
434 * "run" containing the stale entry. (A run is a sequence of entries
435 * between two null slots.)
436 *
437 * @param key the key
438 * @param value the value to be associated with key; meaningful only
439 * if actAsGet is false.
440 * @param staleSlot index of the first stale entry encountered while
441 * searching for key.
442 * @param actAsGet true if this method should act as a get; false
443 * it should act as a set.
444 * @return the value associated with key after the operation completes.
445 */
446 private Object replaceStaleEntry(ThreadLocal key, Object value,
447 int staleSlot, boolean actAsGet) {
448 Entry[] tab = table;
449 int len = tab.length;
450 Entry e;
451
452 // Back up to check for prior stale entry in current run.
453 // We clean out whole runs at a time to avoid continual
454 // incremental rehashing due to garbage collector freeing
455 // up refs in bunches (i.e., whenever the collector runs).
456 int slotToExpunge = staleSlot;
457 for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null;
458 i = prevIndex(i, len))
459 if (e.get() == null)
460 slotToExpunge = i;
461
462 // Find either the key or trailing null slot of run, whichever
463 // occurs first
464 for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null;
465 i = nextIndex(i, len)) {
466 Object k = e.get();
467
468 // If we find key, then we need to swap it
469 // with the stale entry to maintain hash table order.
470 // The newly stale slot, or any other stale slot
471 // encountered above it, can then be sent to expungeStaleEntry
472 // to remove or rehash all of the other entries in run.
473 if (k == key) {
474 if (actAsGet)
475 value = e.value;
476 else
477 e.value = value;
478
479 tab[i] = tab[staleSlot];
480 tab[staleSlot] = e;
481
482 // Start expunge at preceding stale entry if it exists
483 if (slotToExpunge == staleSlot)
484 slotToExpunge = i;
485 expungeStaleEntry(slotToExpunge);
486 return value;
487 }
488
489 // If we didn't find stale entry on backward scan, the
490 // the first stale entry seen while scanning for key is the
491 // first still present in the run.
492 if (k == null && slotToExpunge == staleSlot)
493 slotToExpunge = i;
494 }
495
496 // If key not found, put new entry in stale slot
497 if (actAsGet)
498 value = key.initialValue();
499 tab[staleSlot].value = null; // Help the GC
500 tab[staleSlot] = new Entry(key, value);
501
502 // If there are any other stale entries in run, expunge them
503 if (slotToExpunge != staleSlot)
504 expungeStaleEntry(slotToExpunge);
505
506 return value;
507 }
508
509 /**
510 * Expunge a stale entry by rehashing any possibly colliding entries
511 * lying between staleSlot and the next null slot. This also expunges
512 * any other stale entries encountered before the trailing null. See
513 * Knuth, Section 6.4
514 *
515 * @param staleSlot index of slot known to have null key
516 */
517 private void expungeStaleEntry(int staleSlot) {
518 Entry[] tab = table;
519 int len = tab.length;
520
521 // expunge entry at staleSlot
522 tab[staleSlot].value = null; // Help the GC
523 tab[staleSlot] = null;
524 size--;
525
526 // Rehash until we encounter null
527 Entry e;
528 for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null;
529 i = nextIndex(i, len)) {
530 Object k = e.get();
531 if (k == null) {
532 e.value = null; // Help the GC
533 tab[i] = null;
534 size--;
535 } else {
536 ThreadLocal key = (ThreadLocal)(k);
537 int h = key.threadLocalHashCode & (len - 1);
538 if (h != i) {
539 tab[i] = null;
540
541 // Unlike Knuth 6.4 Algorithm R, we must scan until
542 // null because multiple entries could have been stale.
543 while (tab[h] != null)
544 h = nextIndex(h, len);
545 tab[h] = e;
546 }
547 }
548 }
549 }
550
551 /**
552 * Re-pack and/or re-size the table. First scan the entire
553 * table removing stale entries. If this doesn't sufficiently
554 * shrink the size of the table, double the table size.
555 */
556 private void rehash() {
557 expungeStaleEntries();
558
559 // Use lower threshold for doubling to avoid hysteresis
560 if (size >= threshold - threshold / 4)
561 resize();
562 }
563
564 /**
565 * Double the capacity of the table.
566 */
567 private void resize() {
568 Entry[] oldTab = table;
569 int oldLen = oldTab.length;
570 int newLen = oldLen * 2;
571 Entry[] newTab = new Entry[newLen];
572 int count = 0;
573
574 for (int j = 0; j < oldLen; ++j) {
575 Entry e = oldTab[j];
576 oldTab[j] = null; // Help the GC
577 if (e != null) {
578 Object k = e.get();
579 if (k == null) {
580 e.value = null; // Help the GC
581 } else {
582 ThreadLocal key = (ThreadLocal)(k);
583 int h = key.threadLocalHashCode & (newLen - 1);
584 while (newTab[h] != null)
585 h = nextIndex(h, newLen);
586 newTab[h] = e;
587 count++;
588 }
589 }
590 }
591
592 setThreshold(newLen);
593 size = count;
594 table = newTab;
595 }
596
597 /**
598 * Expunge all stale entries in the table.
599 */
600 private void expungeStaleEntries() {
601 Entry[] tab = table;
602 int len = tab.length;
603 for (int j = 0; j < len; j++) {
604 Entry e = tab[j];
605 if (e != null && e.get() == null)
606 expungeStaleEntry(j);
607 }
608 }
609 }
610 }