| 1 7 8 package java.util.concurrent; 9 import java.util.concurrent.locks.*; 10 import java.util.*; 11 import java.io.Serializable ; 12 import java.io.IOException ; 13 import java.io.ObjectInputStream ; 14 import java.io.ObjectOutputStream ; 15 16 76 public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> 77 implements ConcurrentMap <K, V>, Serializable { 78 private static final long serialVersionUID = 7249069246763182397L; 79 80 84 85 86 87 91 static int DEFAULT_INITIAL_CAPACITY = 16; 92 93 99 static final int MAXIMUM_CAPACITY = 1 << 30; 100 101 105 static final float DEFAULT_LOAD_FACTOR = 0.75f; 106 107 110 static final int DEFAULT_SEGMENTS = 16; 111 112 116 static final int MAX_SEGMENTS = 1 << 16; 118 124 static final int RETRIES_BEFORE_LOCK = 2; 125 126 127 128 132 final int segmentMask; 133 134 137 final int segmentShift; 138 139 142 final Segment[] segments; 143 144 transient Set<K> keySet; 145 transient Set<Map.Entry<K,V>> entrySet; 146 transient Collection<V> values; 147 148 149 150 156 static int hash(Object x) { 157 int h = x.hashCode(); 158 h += ~(h << 9); 159 h ^= (h >>> 14); 160 h += (h << 4); 161 h ^= (h >>> 10); 162 return h; 163 } 164 165 170 final Segment<K,V> segmentFor(int hash) { 171 return (Segment<K,V>) segments[(hash >>> segmentShift) & segmentMask]; 172 } 173 174 175 176 188 static final class HashEntry<K,V> { 189 final K key; 190 final int hash; 191 volatile V value; 192 final HashEntry<K,V> next; 193 194 HashEntry(K key, int hash, HashEntry<K,V> next, V value) { 195 this.key = key; 196 this.hash = hash; 197 this.next = next; 198 this.value = value; 199 } 200 } 201 202 207 static final class Segment<K,V> extends ReentrantLock implements Serializable { 208 244 245 private static final long serialVersionUID = 2249069246763182397L; 246 247 250 transient volatile int count; 251 252 260 transient int modCount; 261 262 267 transient int threshold; 268 269 273 transient volatile HashEntry[] table; 274 275 281 final float loadFactor; 282 283 Segment(int initialCapacity, float lf) { 284 loadFactor = lf; 285 setTable(new HashEntry[initialCapacity]); 286 } 287 288 292 void setTable(HashEntry[] newTable) { 293 threshold = (int)(newTable.length * loadFactor); 294 table = newTable; 295 } 296 297 300 HashEntry<K,V> getFirst(int hash) { 301 HashEntry[] tab = table; 302 return (HashEntry<K,V>) tab[hash & (tab.length - 1)]; 303 } 304 305 312 V readValueUnderLock(HashEntry<K,V> e) { 313 lock(); 314 try { 315 return e.value; 316 } finally { 317 unlock(); 318 } 319 } 320 321 322 323 V get(Object key, int hash) { 324 if (count != 0) { HashEntry<K,V> e = getFirst(hash); 326 while (e != null) { 327 if (e.hash == hash && key.equals(e.key)) { 328 V v = e.value; 329 if (v != null) 330 return v; 331 return readValueUnderLock(e); } 333 e = e.next; 334 } 335 } 336 return null; 337 } 338 339 boolean containsKey(Object key, int hash) { 340 if (count != 0) { HashEntry<K,V> e = getFirst(hash); 342 while (e != null) { 343 if (e.hash == hash && key.equals(e.key)) 344 return true; 345 e = e.next; 346 } 347 } 348 return false; 349 } 350 351 boolean containsValue(Object value) { 352 if (count != 0) { HashEntry[] tab = table; 354 int len = tab.length; 355 for (int i = 0 ; i < len; i++) { 356 for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; 357 e != null ; 358 e = e.next) { 359 V v = e.value; 360 if (v == null) v = readValueUnderLock(e); 362 if (value.equals(v)) 363 return true; 364 } 365 } 366 } 367 return false; 368 } 369 370 boolean replace(K key, int hash, V oldValue, V newValue) { 371 lock(); 372 try { 373 HashEntry<K,V> e = getFirst(hash); 374 while (e != null && (e.hash != hash || !key.equals(e.key))) 375 e = e.next; 376 377 boolean replaced = false; 378 if (e != null && oldValue.equals(e.value)) { 379 replaced = true; 380 e.value = newValue; 381 } 382 return replaced; 383 } finally { 384 unlock(); 385 } 386 } 387 388 V replace(K key, int hash, V newValue) { 389 lock(); 390 try { 391 HashEntry<K,V> e = getFirst(hash); 392 while (e != null && (e.hash != hash || !key.equals(e.key))) 393 e = e.next; 394 395 V oldValue = null; 396 if (e != null) { 397 oldValue = e.value; 398 e.value = newValue; 399 } 400 return oldValue; 401 } finally { 402 unlock(); 403 } 404 } 405 406 407 V put(K key, int hash, V value, boolean onlyIfAbsent) { 408 lock(); 409 try { 410 int c = count; 411 if (c++ > threshold) rehash(); 413 HashEntry[] tab = table; 414 int index = hash & (tab.length - 1); 415 HashEntry<K,V> first = (HashEntry<K,V>) tab[index]; 416 HashEntry<K,V> e = first; 417 while (e != null && (e.hash != hash || !key.equals(e.key))) 418 e = e.next; 419 420 V oldValue; 421 if (e != null) { 422 oldValue = e.value; 423 if (!onlyIfAbsent) 424 e.value = value; 425 } 426 else { 427 oldValue = null; 428 ++modCount; 429 tab[index] = new HashEntry<K,V>(key, hash, first, value); 430 count = c; } 432 return oldValue; 433 } finally { 434 unlock(); 435 } 436 } 437 438 void rehash() { 439 HashEntry[] oldTable = table; 440 int oldCapacity = oldTable.length; 441 if (oldCapacity >= MAXIMUM_CAPACITY) 442 return; 443 444 457 458 HashEntry[] newTable = new HashEntry[oldCapacity << 1]; 459 threshold = (int)(newTable.length * loadFactor); 460 int sizeMask = newTable.length - 1; 461 for (int i = 0; i < oldCapacity ; i++) { 462 HashEntry<K,V> e = (HashEntry<K,V>)oldTable[i]; 465 466 if (e != null) { 467 HashEntry<K,V> next = e.next; 468 int idx = e.hash & sizeMask; 469 470 if (next == null) 472 newTable[idx] = e; 473 474 else { 475 HashEntry<K,V> lastRun = e; 477 int lastIdx = idx; 478 for (HashEntry<K,V> last = next; 479 last != null; 480 last = last.next) { 481 int k = last.hash & sizeMask; 482 if (k != lastIdx) { 483 lastIdx = k; 484 lastRun = last; 485 } 486 } 487 newTable[lastIdx] = lastRun; 488 489 for (HashEntry<K,V> p = e; p != lastRun; p = p.next) { 491 int k = p.hash & sizeMask; 492 HashEntry<K,V> n = (HashEntry<K,V>)newTable[k]; 493 newTable[k] = new HashEntry<K,V>(p.key, p.hash, 494 n, p.value); 495 } 496 } 497 } 498 } 499 table = newTable; 500 } 501 502 505 V remove(Object key, int hash, Object value) { 506 lock(); 507 try { 508 int c = count - 1; 509 HashEntry[] tab = table; 510 int index = hash & (tab.length - 1); 511 HashEntry<K,V> first = (HashEntry<K,V>)tab[index]; 512 HashEntry<K,V> e = first; 513 while (e != null && (e.hash != hash || !key.equals(e.key))) 514 e = e.next; 515 516 V oldValue = null; 517 if (e != null) { 518 V v = e.value; 519 if (value == null || value.equals(v)) { 520 oldValue = v; 521 ++modCount; 525 HashEntry<K,V> newFirst = e.next; 526 for (HashEntry<K,V> p = first; p != e; p = p.next) 527 newFirst = new HashEntry<K,V>(p.key, p.hash, 528 newFirst, p.value); 529 tab[index] = newFirst; 530 count = c; } 532 } 533 return oldValue; 534 } finally { 535 unlock(); 536 } 537 } 538 539 void clear() { 540 if (count != 0) { 541 lock(); 542 try { 543 HashEntry[] tab = table; 544 for (int i = 0; i < tab.length ; i++) 545 tab[i] = null; 546 ++modCount; 547 count = 0; } finally { 549 unlock(); 550 } 551 } 552 } 553 } 554 555 556 557 558 559 575 public ConcurrentHashMap(int initialCapacity, 576 float loadFactor, int concurrencyLevel) { 577 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) 578 throw new IllegalArgumentException (); 579 580 if (concurrencyLevel > MAX_SEGMENTS) 581 concurrencyLevel = MAX_SEGMENTS; 582 583 int sshift = 0; 585 int ssize = 1; 586 while (ssize < concurrencyLevel) { 587 ++sshift; 588 ssize <<= 1; 589 } 590 segmentShift = 32 - sshift; 591 segmentMask = ssize - 1; 592 this.segments = new Segment[ssize]; 593 594 if (initialCapacity > MAXIMUM_CAPACITY) 595 initialCapacity = MAXIMUM_CAPACITY; 596 int c = initialCapacity / ssize; 597 if (c * ssize < initialCapacity) 598 ++c; 599 int cap = 1; 600 while (cap < c) 601 cap <<= 1; 602 603 for (int i = 0; i < this.segments.length; ++i) 604 this.segments[i] = new Segment<K,V>(cap, loadFactor); 605 } 606 607 616 public ConcurrentHashMap(int initialCapacity) { 617 this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); 618 } 619 620 624 public ConcurrentHashMap() { 625 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); 626 } 627 628 635 public ConcurrentHashMap(Map<? extends K, ? extends V> t) { 636 this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 637 11), 638 DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); 639 putAll(t); 640 } 641 642 public boolean isEmpty() { 644 final Segment[] segments = this.segments; 645 654 int[] mc = new int[segments.length]; 655 int mcsum = 0; 656 for (int i = 0; i < segments.length; ++i) { 657 if (segments[i].count != 0) 658 return false; 659 else 660 mcsum += mc[i] = segments[i].modCount; 661 } 662 if (mcsum != 0) { 666 for (int i = 0; i < segments.length; ++i) { 667 if (segments[i].count != 0 || 668 mc[i] != segments[i].modCount) 669 return false; 670 } 671 } 672 return true; 673 } 674 675 public int size() { 677 final Segment[] segments = this.segments; 678 long sum = 0; 679 long check = 0; 680 int[] mc = new int[segments.length]; 681 for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { 684 check = 0; 685 sum = 0; 686 int mcsum = 0; 687 for (int i = 0; i < segments.length; ++i) { 688 sum += segments[i].count; 689 mcsum += mc[i] = segments[i].modCount; 690 } 691 if (mcsum != 0) { 692 for (int i = 0; i < segments.length; ++i) { 693 check += segments[i].count; 694 if (mc[i] != segments[i].modCount) { 695 check = -1; break; 697 } 698 } 699 } 700 if (check == sum) 701 break; 702 } 703 if (check != sum) { sum = 0; 705 for (int i = 0; i < segments.length; ++i) 706 segments[i].lock(); 707 for (int i = 0; i < segments.length; ++i) 708 sum += segments[i].count; 709 for (int i = 0; i < segments.length; ++i) 710 segments[i].unlock(); 711 } 712 if (sum > Integer.MAX_VALUE) 713 return Integer.MAX_VALUE; 714 else 715 return (int)sum; 716 } 717 718 719 729 public V get(Object key) { 730 int hash = hash(key); return segmentFor(hash).get(key, hash); 732 } 733 734 744 public boolean containsKey(Object key) { 745 int hash = hash(key); return segmentFor(hash).containsKey(key, hash); 747 } 748 749 760 public boolean containsValue(Object value) { 761 if (value == null) 762 throw new NullPointerException (); 763 764 766 final Segment[] segments = this.segments; 767 int[] mc = new int[segments.length]; 768 769 for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { 771 int sum = 0; 772 int mcsum = 0; 773 for (int i = 0; i < segments.length; ++i) { 774 int c = segments[i].count; 775 mcsum += mc[i] = segments[i].modCount; 776 if (segments[i].containsValue(value)) 777 return true; 778 } 779 boolean cleanSweep = true; 780 if (mcsum != 0) { 781 for (int i = 0; i < segments.length; ++i) { 782 int c = segments[i].count; 783 if (mc[i] != segments[i].modCount) { 784 cleanSweep = false; 785 break; 786 } 787 } 788 } 789 if (cleanSweep) 790 return false; 791 } 792 for (int i = 0; i < segments.length; ++i) 794 segments[i].lock(); 795 boolean found = false; 796 try { 797 for (int i = 0; i < segments.length; ++i) { 798 if (segments[i].containsValue(value)) { 799 found = true; 800 break; 801 } 802 } 803 } finally { 804 for (int i = 0; i < segments.length; ++i) 805 segments[i].unlock(); 806 } 807 return found; 808 } 809 810 825 public boolean contains(Object value) { 826 return containsValue(value); 827 } 828 829 844 public V put(K key, V value) { 845 if (value == null) 846 throw new NullPointerException (); 847 int hash = hash(key); 848 return segmentFor(hash).put(key, hash, value, false); 849 } 850 851 869 public V putIfAbsent(K key, V value) { 870 if (value == null) 871 throw new NullPointerException |