1 25 26 package EDU.oswego.cs.dl.util.concurrent; 27 28 import java.util.Map ; 29 import java.util.AbstractMap ; 30 import java.util.AbstractSet ; 31 import java.util.AbstractCollection ; 32 import java.util.Collection ; 33 import java.util.Set ; 34 import java.util.Iterator ; 35 import java.util.Enumeration ; 36 import java.util.NoSuchElementException ; 37 38 import java.io.Serializable ; 39 import java.io.IOException ; 40 import java.io.ObjectInputStream ; 41 import java.io.ObjectOutputStream ; 42 43 44 127 128 129 public class ConcurrentHashMap 130 extends AbstractMap 131 implements Map , Cloneable , Serializable { 132 133 167 168 171 protected transient Entry[] table; 172 173 174 181 182 protected static final int CONCURRENCY_LEVEL = 32; 183 184 187 188 protected static final int SEGMENT_MASK = CONCURRENCY_LEVEL - 1; 189 190 196 protected final static class Segment implements Serializable { 197 201 protected int count; 202 203 206 protected synchronized int getCount() { return count; } 207 208 211 protected synchronized void synch() {} 212 } 213 214 217 218 protected final Segment[] segments = new Segment[CONCURRENCY_LEVEL]; 219 220 221 225 public static int DEFAULT_INITIAL_CAPACITY = 32; 226 227 228 233 private static final int MINIMUM_CAPACITY = 32; 234 235 240 private static final int MAXIMUM_CAPACITY = 1 << 30; 241 242 246 247 public static final float DEFAULT_LOAD_FACTOR = 0.75f; 248 249 254 protected final float loadFactor; 255 256 261 protected int threshold; 262 263 264 269 270 protected transient volatile int votesForResize; 271 272 273 282 protected static int bitcount(int w) { 283 w -= (0xaaaaaaaa & w) >>> 1; 284 w = (w & 0x33333333) + ((w >>> 2) & 0x33333333); 285 w = (w + (w >>> 4)) & 0x0f0f0f0f; 286 w += w >>> 8; 287 w += w >>> 16; 288 return w & 0xff; 289 } 290 291 295 private int p2capacity(int initialCapacity) { 296 int cap = initialCapacity; 297 298 int result; 300 if (cap > MAXIMUM_CAPACITY || cap < 0) { 301 result = MAXIMUM_CAPACITY; 302 } else { 303 result = MINIMUM_CAPACITY; 304 while (result < cap) 305 result <<= 1; 306 } 307 return result; 308 } 309 310 315 protected static int hash(Object x) { 316 int h = x.hashCode(); 317 return ((h << 7) - h + (h >>> 9) + (h >>> 17)); 321 } 322 323 324 327 protected boolean eq(Object x, Object y) { 328 return x == y || x.equals(y); 329 } 330 331 332 protected Entry[] newTable(int capacity) { 333 threshold = (int)(capacity * loadFactor / CONCURRENCY_LEVEL) + 1; 334 return new Entry[capacity]; 335 } 336 337 354 public ConcurrentHashMap(int initialCapacity, 355 float loadFactor) { 356 if (!(loadFactor > 0)) 357 throw new IllegalArgumentException ("Illegal Load factor: "+ 358 loadFactor); 359 this.loadFactor = loadFactor; 360 for (int i = 0; i < segments.length; ++i) 361 segments[i] = new Segment(); 362 int cap = p2capacity(initialCapacity); 363 table = newTable(cap); 364 } 365 366 376 public ConcurrentHashMap(int initialCapacity) { 377 this(initialCapacity, DEFAULT_LOAD_FACTOR); 378 } 379 380 384 public ConcurrentHashMap() { 385 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 386 } 387 388 393 public ConcurrentHashMap(Map t) { 394 this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 395 MINIMUM_CAPACITY), 396 DEFAULT_LOAD_FACTOR); 397 putAll(t); 398 } 399 400 405 public int size() { 406 int c = 0; 407 for (int i = 0; i < segments.length; ++i) 408 c += segments[i].getCount(); 409 return c; 410 } 411 412 417 public boolean isEmpty() { 418 for (int i = 0; i < segments.length; ++i) 419 if (segments[i].getCount() != 0) 420 return false; 421 return true; 422 } 423 424 425 436 public Object get(Object key) { 437 int hash = hash(key); 439 Entry[] tab = table; 441 int index = hash & (tab.length - 1); 442 Entry first = tab[index]; 443 Entry e; 444 445 for (e = first; e != null; e = e.next) { 446 if (e.hash == hash && eq(key, e.key)) { 447 Object value = e.value; 448 if (value != null) 449 return value; 450 else 451 break; 452 } 453 } 454 455 Segment seg = segments[hash & SEGMENT_MASK]; 457 synchronized(seg) { 458 tab = table; 459 index = hash & (tab.length - 1); 460 Entry newFirst = tab[index]; 461 if (e != null || first != newFirst) { 462 for (e = newFirst; e != null; e = e.next) { 463 if (e.hash == hash && eq(key, e.key)) 464 return e.value; 465 } 466 } 467 return null; 468 } 469 } 470 471 482 483 public boolean containsKey(Object key) { 484 return get(key) != null; 485 } 486 487 488 507 public Object put(Object key, Object value) { 508 if (value == null) 509 throw new NullPointerException (); 510 511 int hash = hash(key); 512 Segment seg = segments[hash & SEGMENT_MASK]; 513 int segcount; 514 Entry[] tab; 515 int votes; 516 517 synchronized(seg) { 518 tab = table; 519 int index = hash & (tab.length-1); 520 Entry first = tab[index]; 521 522 for (Entry e = first; e != null; e = e.next) { 523 if (e.hash == hash && eq(key, e.key)) { 524 Object oldValue = e.value; 525 e.value = value; 526 return oldValue; 527 } 528 } 529 530 Entry newEntry = new Entry(hash, key, value, first); 532 tab[index] = newEntry; 533 534 if ((segcount = ++seg.count) < threshold) 535 return null; 536 537 int bit = (1 << (hash & SEGMENT_MASK)); 538 votes = votesForResize; 539 if ((votes & bit) == 0) 540 votes = votesForResize |= bit; 541 } 542 543 if (bitcount(votes) >= CONCURRENCY_LEVEL / 4 || 547 segcount > (threshold * CONCURRENCY_LEVEL)) 548 resize(0, tab); 549 550 return null; 551 } 552 553 561 562 protected void resize(int index, Entry[] assumedTab) { 563 Segment seg = segments[index]; 564 synchronized(seg) { 565 if (assumedTab == table) { 566 int next = index+1; 567 if (next < segments.length) 568 resize(next, assumedTab); 569 else 570 rehash(); 571 } 572 } 573 } 574 575 579 protected void rehash() { 580 votesForResize = 0; 582 Entry[] oldTable = table; 583 int oldCapacity = oldTable.length; 584 585 if (oldCapacity >= MAXIMUM_CAPACITY) { 586 threshold = Integer.MAX_VALUE; return; 588 } 589 590 int newCapacity = oldCapacity << 1; 591 Entry[] newTable = newTable(newCapacity); 592 int mask = newCapacity - 1; 593 594 607 608 for (int i = 0; i < oldCapacity ; i++) { 609 Entry e = oldTable[i]; 612 613 if (e != null) { 614 int idx = e.hash & mask; 615 Entry next = e.next; 616 617 if (next == null) 619 newTable[idx] = e; 620 621 else { 622 Entry lastRun = e; 624 int lastIdx = idx; 625 for (Entry last = next; last != null; last = last.next) { 626 int k = last.hash & mask; 627 if (k != lastIdx) { 628 lastIdx = k; 629 lastRun = last; 630 } 631 } 632 newTable[lastIdx] = lastRun; 633 634 for (Entry p = e; p != lastRun; p = p.next) { 636 int k = p.hash & mask; 637 newTable[k] = new Entry(p.hash, p.key, 638 p.value, newTable[k]); 639 } 640 } 641 } 642 } 643 644 table = newTable; 645 } 646 647 648 658 public Object remove(Object key) { 659 return remove(key, null); 660 } 661 662 663 677 678 protected Object remove(Object key, Object value) { 679 688 689 int hash = hash(key); 690 Segment seg = segments[hash & SEGMENT_MASK]; 691 692 synchronized(seg) { 693 Entry[] tab = table; 694 int index = hash & (tab.length-1); 695 Entry first = tab[index]; 696 Entry e = first; 697 698 for (;;) { 699 if (e == null) 700 return null; 701 if (e.hash == hash && eq(key, e.key)) 702 break; 703 e = e.next; 704 } 705 706 Object oldValue = e.value; 707 if (value != null && !value.equals(oldValue)) 708 return null; 709 710 e.value = null; 711 712 Entry head = e.next; 713 for (Entry p = first; p != e; p = p.next) 714 head = new Entry(p.hash, p.key, p.value, head); 715 tab[index] = head; 716 seg.count--; 717 return oldValue; 718 } 719 } 720 721 722 733 public boolean containsValue(Object value) { 734 735 if (value == null) throw new NullPointerException (); 736 737 for (int s = 0; s < segments.length; ++s) { 738 Segment seg = segments[s]; 739 Entry[] tab; 740 synchronized(seg) { tab = table; } 741 for (int i = s; i < tab.length; i+= segments.length) { 742 for (Entry e = tab[i]; e != null; e = e.next) 743 if (value.equals(e.value)) 744 return true; 745 } 746 } 747 return false; 748 } 749 750 768 769 public boolean contains(Object value) { 770 return containsValue(value); 771 } 772 773 781 782 public void putAll(Map t) { 783 int n = t.size(); 784 if (n == 0) 785 return; 786 787 for(;;) { 791 Entry[] tab; 792 int max; 793 synchronized(segments[0]) { tab = table; 795 max = threshold * CONCURRENCY_LEVEL; 796 } 797 if (n < max) 798 break; 799 resize(0, tab); 800 } 801 802 for (Iterator it = t.entrySet().iterator(); it.hasNext();) { 803 Map.Entry entry = (Map.Entry ) it.next(); 804 put(entry.getKey(), entry.getValue()); 805 } 806 } 807 808 811 812 public void clear() { 813 for (int s = 0; s < segments.length; ++s) { 816 Segment seg = segments[s]; 817 synchronized(seg) { 818 Entry[] tab = table; 819 for (int i = s; i < tab.length; i+= segments.length) { 820 for (Entry e = tab[i]; e != null; e = e.next) 821 e.value = null; 822 tab[i] = null; 823 seg.count = 0; 824 } 825 } 826 } 827 } 828 829 836 837 public Object clone() { 838 return new ConcurrentHashMap(this); 841 } 842 843 845 protected transient Set keySet = null; 846 protected transient Set entrySet = null; 847 protected transient Collection values = null; 848 849 860 861 public Set keySet() { 862 Set ks = keySet; 863 return (ks != null)? ks : (keySet = new KeySet()); 864 } 865 866 private class KeySet extends AbstractSet { 867 public Iterator iterator() { 868 return new KeyIterator(); 869 } 870 public int size() { 871 return ConcurrentHashMap.this.size(); 872 } 873 public boolean contains(Object o) { 874 return ConcurrentHashMap.this.containsKey(o); 875 } 876 public boolean remove(Object o) { 877 return ConcurrentHashMap.this.remove(o) != null; 878 } 879 public void clear() { 880 ConcurrentHashMap.this.clear(); 881 } 882 } 883 884 895 896 public Collection values() { 897 Collection vs = values; 898 return (vs != null)? vs : (values = new Values()); 899 } 900 901 private class Values extends AbstractCollection { 902 public Iterator iterator() { 903 return new ValueIterator(); 904 } 905 public int size() { 906 return ConcurrentHashMap.this.size(); 907 } 908 public boolean contains(Object o) { 909 return ConcurrentHashMap.this.containsValue(o); 910 } 911 public void clear() { 912 ConcurrentHashMap.this.clear(); 913 } 914 } 915 916 928 929 public Set entrySet() { 930 Set es = entrySet; 931 return (es != null) ? es : (entrySet = new EntrySet()); 932 } 933 934 private class EntrySet extends AbstractSet { 935 public Iterator iterator() { 936 return new HashIterator(); 937 } 938 public boolean contains(Object o) { 939 if (!(o instanceof Map.Entry )) 940 return false; 941 Map.Entry entry = (Map.Entry )o; 942 Object v = ConcurrentHashMap.this.get(entry.getKey()); 943 return v != null && v.equals(entry.getValue()); 944 } 945 public boolean remove(Object o) { 946 if (!(o instanceof Map.Entry )) 947 return false; 948 Map.Entry e = (Map.Entry )o; 949 return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()) != null; 950 } 951 public int size() { 952 return ConcurrentHashMap.this.size(); 953 } 954 public void clear() { 955 ConcurrentHashMap.this.clear(); 956 } 957 } 958 959 968 public Enumeration keys() { 969 return new KeyIterator(); 970 } 971 972 983 984 public Enumeration elements() { 985 return new ValueIterator(); 986 } 987 988 991 992 protected static class Entry implements Map.Entry { 993 999 1000 protected final Object key; 1001 protected volatile Object value; 1002 protected final int hash; 1003 protected final Entry next; 1004 1005 Entry(int hash, Object key, Object value, Entry next) { 1006 this.value = value; 1007 this.hash = hash; 1008 this.key = key; 1009 this.next = next; 1010 } 1011 1012 1014 public Object getKey() { 1015 return key; 1016 } 1017 1018 1029 public Object getValue() { 1030 return value; 1031 } 1032 1033 1052 1053 public Object setValue(Object value) { 1054 if (value == null) 1055 throw new NullPointerException (); 1056 Object oldValue = this.value; 1057 this.value = value; 1058 return oldValue; 1059 } 1060 1061 public boolean equals(Object o) { 1062 if (!(o instanceof Map.Entry )) 1063 return false; 1064 Map.Entry e = (Map.Entry )o; 1065 return (key.equals(e.getKey()) && value.equals(e.getValue())); 1066 } 1067 1068 public int hashCode() { 1069 return key.hashCode() ^ value.hashCode(); 1070 } 1071 1072 public String toString() { 1073 return key + "=" + value; 1074 } 1075 1076 } 1077 1078 protected class HashIterator implements Iterator , Enumeration { 1079 protected final Entry[] tab; protected int index; protected Entry entry = null; protected Object currentKey; protected Object currentValue; protected Entry lastReturned = null; 1086 protected HashIterator() { 1087 synchronized(segments[0]) { tab = table; } 1089 for (int i = 1; i < segments.length; ++i) segments[i].synch(); 1090 index = tab.length - 1; 1091 } 1092 1093 public boolean hasMoreElements() { return hasNext(); } 1094 public Object nextElement() { return next(); } 1095 1096 public boolean hasNext() { 1097 1104 1105 for (;;) { 1106 if (entry != null) { 1107 Object v = entry.value; 1108 if (v != null) { 1109 currentKey = entry.key; 1110 currentValue = v; 1111 return true; 1112 } 1113 else 1114 entry = entry.next; 1115 } 1116 1117 while (entry == null && index >= 0) 1118 entry = tab[index--]; 1119 1120 if (entry == null) { 1121 currentKey = currentValue = null; 1122 return false; 1123 } 1124 } 1125 } 1126 1127 protected Object returnValueOfNext() { return entry; } 1128 1129 public Object next() { 1130 if (currentKey == null && !hasNext()) 1131 throw new NoSuchElementException (); 1132 1133 Object result = returnValueOfNext(); 1134 lastReturned = entry; 1135 currentKey = currentValue = null; 1136 entry = entry.next; 1137 return result; 1138 } 1139 1140 public void remove() { 1141 if (lastReturned == null) 1142 throw new IllegalStateException (); 1143 ConcurrentHashMap.this.remove(lastReturned.key); 1144 lastReturned = null; 1145 } 1146 1147 } 1148 1149 protected class KeyIterator extends HashIterator { 1150 protected Object returnValueOfNext() { return currentKey; } 1151 } 1152 1153 protected class ValueIterator extends HashIterator { 1154 protected Object returnValueOfNext() { return currentValue; } 1155 } 1156 1157 1168 1169 private void writeObject(java.io.ObjectOutputStream s) 1170 throws IOException { 1171 s.defaultWriteObject(); 1173 1174 1178 int cap; 1179 synchronized(segments[0]) { cap = table.length; } 1180 s.writeInt(cap); 1181 1182 for (int k = 0; k < segments.length; ++k) { 1184 Segment seg = segments[k]; 1185 Entry[] tab; 1186 synchronized(seg) { tab = table; } 1187 for (int i = k; i < tab.length; i+= segments.length) { 1188 for (Entry e = tab[i]; e != null; e = e.next) { 1189 s.writeObject(e.key); 1190 s.writeObject(e.value); 1191 } 1192 } 1193 } 1194 1195 s.writeObject(null); 1196 s.writeObject(null); 1197 } 1198 1199 1204 private void readObject(java.io.ObjectInputStream s) 1205 throws IOException , ClassNotFoundException { 1206 s.defaultReadObject(); 1208 1209 int cap = s.readInt(); 1210 table = newTable(cap); 1211 for (int i = 0; i < segments.length; ++i) 1212 segments[i] = new Segment(); 1213 1214 1215 for (;;) { 1217 Object key = s.readObject(); 1218 Object value = s.readObject(); 1219 if (key == null) 1220 break; 1221 put(key, value); 1222 } 1223 } 1224} 1225 | Popular Tags |