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 |
} |