1 7 8 package java.lang; 9 import java.lang.ref.*; 10 11 52 public class ThreadLocal<T> { 53 62 private final int threadLocalHashCode = nextHashCode(); 63 64 67 private static int nextHashCode = 0; 68 69 74 private static final int HASH_INCREMENT = 0x61c88647; 75 76 83 private static synchronized int nextHashCode() { 84 int h = nextHashCode; 85 nextHashCode = h + HASH_INCREMENT; 86 return h; 87 } 88 89 106 protected T initialValue() { 107 return null; 108 } 109 110 113 public ThreadLocal() { 114 } 115 116 123 public T get() { 124 Thread t = Thread.currentThread(); 125 ThreadLocalMap map = getMap(t); 126 if (map != null) 127 return (T)map.get(this); 128 129 T value = initialValue(); 133 createMap(t, value); 134 return value; 135 } 136 137 146 public void set(T value) { 147 Thread t = Thread.currentThread(); 148 ThreadLocalMap map = getMap(t); 149 if (map != null) 150 map.set(this, value); 151 else 152 createMap(t, value); 153 } 154 155 162 163 public void remove() { 164 ThreadLocalMap m = getMap(Thread.currentThread()); 165 if (m != null) 166 m.remove(this); 167 } 168 169 176 ThreadLocalMap getMap(Thread t) { 177 return t.threadLocals; 178 } 179 180 188 void createMap(Thread t, T firstValue) { 189 t.threadLocals = new ThreadLocalMap(this, firstValue); 190 } 191 192 199 static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { 200 return new ThreadLocalMap(parentMap); 201 } 202 203 211 T childValue(T parentValue) { 212 throw new UnsupportedOperationException (); 213 } 214 215 225 static class ThreadLocalMap { 226 227 235 private static class Entry extends WeakReference<ThreadLocal > { 236 237 private Object value; 238 239 private Entry(ThreadLocal k, Object v) { 240 super(k); 241 value = v; 242 } 243 } 244 245 248 private static final int INITIAL_CAPACITY = 16; 249 250 254 private Entry[] table; 255 256 259 private int size = 0; 260 261 264 private int threshold; 266 269 private void setThreshold(int len) { 270 threshold = len * 2 / 3; 271 } 272 273 276 private static int nextIndex(int i, int len) { 277 return ((i + 1 < len) ? i + 1 : 0); 278 } 279 280 283 private static int prevIndex(int i, int len) { 284 return ((i - 1 >= 0) ? i - 1 : len - 1); 285 } 286 287 292 ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { 293 table = new Entry[INITIAL_CAPACITY]; 294 int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); 295 table[i] = new Entry(firstKey, firstValue); 296 size = 1; 297 setThreshold(INITIAL_CAPACITY); 298 } 299 300 306 private ThreadLocalMap(ThreadLocalMap parentMap) { 307 Entry[] parentTable = parentMap.table; 308 int len = parentTable.length; 309 setThreshold(len); 310 table = new Entry[len]; 311 312 for (int j = 0; j < len; j++) { 313 Entry e = parentTable[j]; 314 if (e != null) { 315 ThreadLocal k = e.get(); 316 if (k != null) { 317 ThreadLocal key = k; 318 Object value = key.childValue(e.value); 319 Entry c = new Entry(key, value); 320 int h = key.threadLocalHashCode & (len - 1); 321 while (table[h] != null) 322 h = nextIndex(h, len); 323 table[h] = c; 324 size++; 325 } 326 } 327 } 328 } 329 330 341 private Object get(ThreadLocal key) { 342 int i = key.threadLocalHashCode & (table.length - 1); 343 Entry e = table[i]; 344 if (e != null && e.get() == key) 345 return e.value; 346 347 return getAfterMiss(key, i, e); 348 } 349 350 359 private Object getAfterMiss(ThreadLocal key, int i, Entry e) { 360 Entry[] tab = table; 361 int len = tab.length; 362 363 while (e != null) { 364 ThreadLocal k = e.get(); 365 if (k == key) 366 return e.value; 367 if (k == null) 368 return replaceStaleEntry(key, null, i, true); 369 370 i = nextIndex(i, len); 371 e = tab[i]; 372 } 373 374 Object value = key.initialValue(); 375 tab[i] = new Entry(key, value); 376 int sz = ++size; 377 if (!cleanSomeSlots(i, sz) && sz >= threshold) 378 rehash(); 379 380 return value; 381 } 382 383 384 390 private void set(ThreadLocal key, Object value) { 391 392 397 Entry[] tab = table; 398 int len = tab.length; 399 int i = key.threadLocalHashCode & (len-1); 400 401 for (Entry e = tab[i]; 402 e != null; 403 e = tab[i = nextIndex(i, len)]) { 404 ThreadLocal k = e.get(); 405 406 if (k == key) { 407 e.value = value; 408 return; 409 } 410 411 if (k == null) { 412 replaceStaleEntry(key, value, i, false); 413 return; 414 } 415 } 416 417 tab[i] = new Entry(key, value); 418 int sz = ++size; 419 if (!cleanSomeSlots(i, sz) && sz >= threshold) 420 rehash(); 421 } 422 423 426 private void remove(ThreadLocal key) { 427 Entry[] tab = table; 428 int len = tab.length; 429 int i = key.threadLocalHashCode & (len-1); 430 for (Entry e = tab[i]; 431 e != null; 432 e = tab[i = nextIndex(i, len)]) { 433 if (e.get() == key) { 434 e.clear(); 435 expungeStaleEntry(i); 436 return; 437 } 438 } 439 } 440 441 463 private Object replaceStaleEntry(ThreadLocal key, Object value, 464 int staleSlot, boolean actAsGet) { 465 Entry[] tab = table; 466 int len = tab.length; 467 Entry e; 468 469 int slotToExpunge = staleSlot; 474 for (int i = prevIndex(staleSlot, len); 475 (e = tab[i]) != null; 476 i = prevIndex(i, len)) 477 if (e.get() == null) 478 slotToExpunge = i; 479 480 for (int i = nextIndex(staleSlot, len); 483 (e = tab[i]) != null; 484 i = nextIndex(i, len)) { 485 ThreadLocal k = e.get(); 486 487 if (k == key) { 493 if (actAsGet) 494 value = e.value; 495 else 496 e.value = value; 497 498 tab[i] = tab[staleSlot]; 499 tab[staleSlot] = e; 500 501 if (slotToExpunge == staleSlot) 503 slotToExpunge = i; 504 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); 505 return value; 506 } 507 508 if (k == null && slotToExpunge == staleSlot) 512 slotToExpunge = i; 513 } 514 515 if (actAsGet) 517 value = key.initialValue(); 518 tab[staleSlot].value = null; tab[staleSlot] = new Entry(key, value); 520 521 if (slotToExpunge != staleSlot) 523 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); 524 525 return value; 526 } 527 528 539 private int expungeStaleEntry(int staleSlot) { 540 Entry[] tab = table; 541 int len = tab.length; 542 543 tab[staleSlot].value = null; tab[staleSlot] = null; 546 size--; 547 548 Entry e; 550 int i; 551 for (i = nextIndex(staleSlot, len); 552 (e = tab[i]) != null; 553 i = nextIndex(i, len)) { 554 ThreadLocal k = e.get(); 555 if (k == null) { 556 e.value = null; tab[i] = null; 558 size--; 559 } else { 560 ThreadLocal key = k; 561 int h = key.threadLocalHashCode & (len - 1); 562 if (h != i) { 563 tab[i] = null; 564 565 while (tab[h] != null) 568 h = nextIndex(h, len); 569 tab[h] = e; 570 } 571 } 572 } 573 return i; 574 } 575 576 600 private boolean cleanSomeSlots(int i, int n) { 601 boolean removed = false; 602 Entry[] tab = table; 603 int len = tab.length; 604 do { 605 i = nextIndex(i, len); 606 Entry e = tab[i]; 607 if (e != null && e.get() == null) { 608 n = len; 609 removed = true; 610 i = expungeStaleEntry(i); 611 } 612 } while ( (n >>>= 1) != 0); 613 return removed; 614 } 615 616 621 private void rehash() { 622 expungeStaleEntries(); 623 624 if (size >= threshold - threshold / 4) 626 resize(); 627 } 628 629 632 private void resize() { 633 Entry[] oldTab = table; 634 int oldLen = oldTab.length; 635 int newLen = oldLen * 2; 636 Entry[] newTab = new Entry[newLen]; 637 int count = 0; 638 639 for (int j = 0; j < oldLen; ++j) { 640 Entry e = oldTab[j]; 641 oldTab[j] = null; if (e != null) { 643 ThreadLocal k = e.get(); 644 if (k == null) { 645 e.value = null; } else { 647 ThreadLocal key = k; 648 int h = key.threadLocalHashCode & (newLen - 1); 649 while (newTab[h] != null) 650 h = nextIndex(h, newLen); 651 newTab[h] = e; 652 count++; 653 } 654 } 655 } 656 657 setThreshold(newLen); 658 size = count; 659 table = newTab; 660 } 661 662 665 private void expungeStaleEntries() { 666 Entry[] tab = table; 667 int len = tab.length; 668 for (int j = 0; j < len; j++) { 669 Entry e = tab[j]; 670 if (e != null && e.get() == null) 671 expungeStaleEntry(j); 672 } 673 } 674 } 675 } 676 | Popular Tags |