1 28 29 package EDU.oswego.cs.dl.util.concurrent; 30 31 import java.util.Map ; 32 import java.util.AbstractMap ; 33 import java.util.AbstractSet ; 34 import java.util.AbstractCollection ; 35 import java.util.Collection ; 36 import java.util.Set ; 37 import java.util.Iterator ; 38 import java.util.Enumeration ; 39 import java.util.ConcurrentModificationException ; 40 import java.util.NoSuchElementException ; 41 42 import java.io.Serializable ; 43 import java.io.IOException ; 44 import java.io.ObjectInputStream ; 45 import java.io.ObjectOutputStream ; 46 47 48 151 152 153 public class ConcurrentReaderHashMap 154 extends AbstractMap 155 implements Map , Cloneable , Serializable { 156 157 158 181 182 183 protected static class BarrierLock implements java.io.Serializable { } 184 185 188 protected final BarrierLock barrierLock = new BarrierLock(); 189 190 193 194 protected transient Object lastWrite; 195 196 201 protected final void recordModification(Object x) { 202 synchronized(barrierLock) { 203 lastWrite = x; 204 } 205 } 206 207 212 protected final Entry[] getTableForReading() { 213 synchronized(barrierLock) { 214 return table; 215 } 216 } 217 218 219 223 public static int DEFAULT_INITIAL_CAPACITY = 32; 224 225 226 231 private static final int MINIMUM_CAPACITY = 4; 232 233 238 private static final int MAXIMUM_CAPACITY = 1 << 30; 239 240 244 245 public static final float DEFAULT_LOAD_FACTOR = 0.75f; 246 247 248 251 protected transient Entry[] table; 252 253 256 protected transient int count; 257 258 264 protected int threshold; 265 266 271 protected float loadFactor; 272 273 277 private int p2capacity(int initialCapacity) { 278 int cap = initialCapacity; 279 280 int result; 282 if (cap > MAXIMUM_CAPACITY || cap < 0) { 283 result = MAXIMUM_CAPACITY; 284 } else { 285 result = MINIMUM_CAPACITY; 286 while (result < cap) 287 result <<= 1; 288 } 289 return result; 290 } 291 292 297 private static int hash(Object x) { 298 int h = x.hashCode(); 299 return ((h << 7) - h + (h >>> 9) + (h >>> 17)); 303 } 304 305 308 protected boolean eq(Object x, Object y) { 309 return x == y || x.equals(y); 310 } 311 312 323 324 public ConcurrentReaderHashMap(int initialCapacity, float loadFactor) { 325 if (loadFactor <= 0) 326 throw new IllegalArgumentException ("Illegal Load factor: "+ 327 loadFactor); 328 this.loadFactor = loadFactor; 329 330 int cap = p2capacity(initialCapacity); 331 332 table = new Entry[cap]; 333 threshold = (int)(cap * loadFactor); 334 } 335 336 346 347 public ConcurrentReaderHashMap(int initialCapacity) { 348 this(initialCapacity, DEFAULT_LOAD_FACTOR); 349 } 350 351 355 356 public ConcurrentReaderHashMap() { 357 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 358 } 359 360 365 366 public ConcurrentReaderHashMap(Map t) { 367 this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16), 368 DEFAULT_LOAD_FACTOR); 369 putAll(t); 370 } 371 372 377 378 public synchronized int size() { 379 return count; 380 } 381 382 387 388 public synchronized boolean isEmpty() { 389 return count == 0; 390 } 391 392 393 394 405 406 407 public Object get(Object key) { 408 409 int hash = hash(key); 411 412 420 421 Entry[] tab = table; 422 int index = hash & (tab.length - 1); 423 Entry first = tab[index]; 424 Entry e = first; 425 426 for (;;) { 427 if (e == null) { 428 429 432 Entry[] reread = getTableForReading(); 433 if (tab == reread && first == tab[index]) 434 return null; 435 else { 436 tab = reread; 438 e = first = tab[index = hash & (tab.length-1)]; 439 } 440 441 } 442 443 else if (e.hash == hash && eq(key, e.key)) { 444 Object value = e.value; 445 if (value != null) 446 return value; 447 448 453 synchronized(this) { 454 tab = table; 455 } 456 e = first = tab[index = hash & (tab.length-1)]; 457 458 } 459 else 460 e = e.next; 461 } 462 } 463 464 465 476 477 478 public boolean containsKey(Object key) { 479 return get(key) != null; 480 } 481 482 499 500 public Object put(Object key, Object value) { 501 if (value == null) 502 throw new NullPointerException (); 503 504 int hash = hash(key); 505 Entry[] tab = table; 506 int index = hash & (tab.length-1); 507 Entry first = tab[index]; 508 Entry e; 509 510 for (e = first; e != null; e = e.next) 511 if (e.hash == hash && eq(key, e.key)) 512 break; 513 514 synchronized(this) { 515 if (tab == table) { 516 if (e == null) { 517 if (first == tab[index]) { 519 Entry newEntry = new Entry(hash, key, value, first); 521 tab[index] = newEntry; 522 if (++count >= threshold) rehash(); 523 else recordModification(newEntry); 524 return null; 525 } 526 } 527 else { 528 Object oldValue = e.value; 529 if (first == tab[index] && oldValue != null) { 530 e.value = value; 531 return oldValue; 532 } 533 } 534 } 535 536 return sput(key, value, hash); 538 } 539 } 540 541 542 546 protected Object sput(Object key, Object value, int hash) { 547 548 Entry[] tab = table; 549 int index = hash & (tab.length-1); 550 Entry first = tab[index]; 551 Entry e = first; 552 553 for (;;) { 554 if (e == null) { 555 Entry newEntry = new Entry(hash, key, value, first); 556 tab[index] = newEntry; 557 if (++count >= threshold) rehash(); 558 else recordModification(newEntry); 559 return null; 560 } 561 else if (e.hash == hash && eq(key, e.key)) { 562 Object oldValue = e.value; 563 e.value = value; 564 return oldValue; 565 } 566 else 567 e = e.next; 568 } 569 } 570 571 572 577 protected void rehash() { 578 Entry[] oldTable = table; 579 int oldCapacity = oldTable.length; 580 if (oldCapacity >= MAXIMUM_CAPACITY) { 581 threshold = Integer.MAX_VALUE; return; 583 } 584 585 int newCapacity = oldCapacity << 1; 586 int mask = newCapacity - 1; 587 threshold = (int)(newCapacity * loadFactor); 588 589 Entry[] newTable = new Entry[newCapacity]; 590 603 604 for (int i = 0; i < oldCapacity ; i++) { 605 Entry e = oldTable[i]; 608 609 if (e != null) { 610 int idx = e.hash & mask; 611 Entry next = e.next; 612 613 if (next == null) 615 newTable[idx] = e; 616 617 else { 618 Entry lastRun = e; 620 int lastIdx = idx; 621 for (Entry last = next; last != null; last = last.next) { 622 int k = last.hash & mask; 623 if (k != lastIdx) { 624 lastIdx = k; 625 lastRun = last; 626 } 627 } 628 newTable[lastIdx] = lastRun; 629 630 for (Entry p = e; p != lastRun; p = p.next) { 632 int k = p.hash & mask; 633 newTable[k] = new Entry(p.hash, p.key, 634 p.value, newTable[k]); 635 } 636 } 637 } 638 } 639 640 table = newTable; 641 recordModification(newTable); 642 } 643 644 654 655 public Object remove(Object key) { 656 665 666 667 int hash = hash(key); 668 Entry[] tab = table; 669 int index = hash & (tab.length-1); 670 Entry first = tab[index]; 671 Entry e = first; 672 673 for (e = first; e != null; e = e.next) 674 if (e.hash == hash && eq(key, e.key)) 675 break; 676 677 678 synchronized(this) { 679 if (tab == table) { 680 if (e == null) { 681 if (first == tab[index]) 682 return null; 683 } 684 else { 685 Object oldValue = e.value; 686 if (first == tab[index] && oldValue != null) { 687 e.value = null; 688 count--; 689 690 Entry head = e.next; 691 for (Entry p = first; p != e; p = p.next) 692 head = new Entry(p.hash, p.key, p.value, head); 693 694 tab[index] = head; 695 recordModification(head); 696 return oldValue; 697 } 698 } 699 } 700 701 return sremove(key, hash); 703 } 704 } 705 706 710 711 protected Object sremove(Object key, int hash) { 712 Entry[] tab = table; 713 int index = hash & (tab.length-1); 714 Entry first = tab[index]; 715 716 for (Entry e = first; e != null; e = e.next) { 717 if (e.hash == hash && eq(key, e.key)) { 718 Object oldValue = e.value; 719 e.value = null; 720 count--; 721 Entry head = e.next; 722 for (Entry p = first; p != e; p = p.next) 723 head = new Entry(p.hash, p.key, p.value, head); 724 725 tab[index] = head; 726 recordModification(head); 727 return oldValue; 728 } 729 } 730 return null; 731 } 732 733 734 745 746 public boolean containsValue(Object value) { 747 if (value == null) throw new NullPointerException (); 748 749 Entry tab[] = getTableForReading(); 750 751 for (int i = 0 ; i < tab.length; ++i) { 752 for (Entry e = tab[i] ; e != null ; e = e.next) 753 if (value.equals(e.value)) 754 return true; 755 } 756 757 return false; 758 } 759 760 778 779 public boolean contains(Object value) { 780 return containsValue(value); 781 } 782 783 784 792 793 public synchronized void putAll(Map t) { 794 int n = t.size(); 795 if (n == 0) 796 return; 797 798 while (n >= threshold) 802 rehash(); 803 804 for (Iterator it = t.entrySet().iterator(); it.hasNext();) { 805 Map.Entry entry = (Map.Entry ) it.next(); 806 Object key = entry.getKey(); 807 Object value = entry.getValue(); 808 put(key, value); 809 } 810 } 811 812 813 816 public synchronized void clear() { 817 Entry tab[] = table; 818 for (int i = 0; i < tab.length ; ++i) { 819 820 for (Entry e = tab[i]; e != null; e = e.next) 822 e.value = null; 823 824 tab[i] = null; 825 } 826 count = 0; 827 recordModification(tab); 828 } 829 830 837 838 public synchronized Object clone() { 839 try { 840 ConcurrentReaderHashMap t = (ConcurrentReaderHashMap)super.clone(); 841 842 t.keySet = null; 843 t.entrySet = null; 844 t.values = null; 845 846 Entry[] tab = table; 847 t.table = new Entry[tab.length]; 848 Entry[] ttab = t.table; 849 850 for (int i = 0; i < tab.length; ++i) { 851 Entry first = null; 852 for (Entry e = tab[i]; e != null; e = e.next) 853 first = new Entry(e.hash, e.key, e.value, first); 854 ttab[i] = first; 855 } 856 857 return t; 858 } 859 catch (CloneNotSupportedException e) { 860 throw new InternalError (); 862 } 863 } 864 865 867 protected transient Set keySet = null; 868 protected transient Set entrySet = null; 869 protected transient Collection values = null; 870 871 882 883 public Set keySet() { 884 Set ks = keySet; 885 return (ks != null)? ks : (keySet = new KeySet()); 886 } 887 888 private class KeySet extends AbstractSet { 889 public Iterator iterator() { 890 return new KeyIterator(); 891 } 892 public int size() { 893 return ConcurrentReaderHashMap.this.size(); 894 } 895 public boolean contains(Object o) { 896 return ConcurrentReaderHashMap.this.containsKey(o); 897 } 898 public boolean remove(Object o) { 899 return ConcurrentReaderHashMap.this.remove(o) != null; 900 } 901 public void clear() { 902 ConcurrentReaderHashMap.this.clear(); 903 } 904 } 905 906 917 918 public Collection values() { 919 Collection vs = values; 920 return (vs != null)? vs : (values = new Values()); 921 } 922 923 private class Values extends AbstractCollection { 924 public Iterator iterator() { 925 return new ValueIterator(); 926 } 927 public int size() { 928 return ConcurrentReaderHashMap.this.size(); 929 } 930 public boolean contains(Object o) { 931 return ConcurrentReaderHashMap.this.containsValue(o); 932 } 933 public void clear() { 934 ConcurrentReaderHashMap.this.clear(); 935 } 936 } 937 938 950 951 public Set entrySet() { 952 Set es = entrySet; 953 return (es != null) ? es : (entrySet = new EntrySet()); 954 } 955 956 private class EntrySet extends AbstractSet { 957 public Iterator iterator() { 958 return new HashIterator(); 959 } 960 public boolean contains(Object o) { 961 if (!(o instanceof Map.Entry )) 962 return false; 963 Map.Entry entry = (Map.Entry )o; 964 Object v = ConcurrentReaderHashMap.this.get(entry.getKey()); 965 return v != null && v.equals(entry.getValue()); 966 } 967 public boolean remove(Object o) { 968 if (!(o instanceof Map.Entry )) 969 return false; 970 return ConcurrentReaderHashMap.this.findAndRemoveEntry((Map.Entry )o); 971 } 972 public int size() { 973 return ConcurrentReaderHashMap.this.size(); 974 } 975 public void clear() { 976 ConcurrentReaderHashMap.this.clear(); 977 } 978 } 979 980 983 protected synchronized boolean findAndRemoveEntry(Map.Entry entry) { 984 Object key = entry.getKey(); 985 Object v = get(key); 986 if (v != null && v.equals(entry.getValue())) { 987 remove(key); 988 return true; 989 } 990 else 991 return false; 992 } 993 994 1003 public Enumeration keys() { 1004 return new KeyIterator(); 1005 } 1006 1007 1018 1019 public Enumeration elements() { 1020 return new ValueIterator(); 1021 } 1022 1023 1024 1027 1028 protected static class Entry implements Map.Entry { 1029 1030 1036 1037 protected final int hash; 1038 protected final Object key; 1039 protected final Entry next; 1040 protected volatile Object value; 1041 1042 Entry(int hash, Object key, Object value, Entry next) { 1043 this.hash = hash; 1044 this.key = key; 1045 this.next = next; 1046 this.value = value; 1047 } 1048 1049 1051 public Object getKey() { 1052 return key; 1053 } 1054 1055 1067 public Object getValue() { 1068 return value; 1069 } 1070 1071 1091 1092 public Object setValue(Object value) { 1093 if (value == null) 1094 throw new NullPointerException (); 1095 Object oldValue = this.value; 1096 this.value = value; 1097 return oldValue; 1098 } 1099 1100 public boolean equals(Object o) { 1101 if (!(o instanceof Map.Entry )) 1102 return false; 1103 Map.Entry e = (Map.Entry )o; 1104 return (key.equals(e.getKey()) && value.equals(e.getValue())); 1105 } 1106 1107 public int hashCode() { 1108 return key.hashCode() ^ value.hashCode(); 1109 } 1110 1111 public String toString() { 1112 return key + "=" + value; 1113 } 1114 1115 } 1116 1117 protected class HashIterator implements Iterator , Enumeration { 1118 protected final Entry[] tab; protected int index; protected Entry entry = null; protected Object currentKey; protected Object currentValue; protected Entry lastReturned = null; 1125 protected HashIterator() { 1126 tab = ConcurrentReaderHashMap.this.getTableForReading(); 1127 index = tab.length - 1; 1128 } 1129 1130 public boolean hasMoreElements() { return hasNext(); } 1131 public Object nextElement() { return next(); } 1132 1133 1134 public boolean hasNext() { 1135 1136 1143 1144 for (;;) { 1145 if (entry != null) { 1146 Object v = entry.value; 1147 if (v != null) { 1148 currentKey = entry.key; 1149 currentValue = v; 1150 return true; 1151 } 1152 else 1153 entry = entry.next; 1154 } 1155 1156 while (entry == null && index >= 0) 1157 entry = tab[index--]; 1158 1159 if (entry == null) { 1160 currentKey = currentValue = null; 1161 return false; 1162 } 1163 } 1164 } 1165 1166 protected Object returnValueOfNext() { return entry; } 1167 1168 public Object next() { 1169 if (currentKey == null && !hasNext()) 1170 throw new NoSuchElementException (); 1171 1172 Object result = returnValueOfNext(); 1173 lastReturned = entry; 1174 currentKey = currentValue = null; 1175 entry = entry.next; 1176 return result; 1177 } 1178 1179 public void remove() { 1180 if (lastReturned == null) 1181 throw new IllegalStateException (); 1182 ConcurrentReaderHashMap.this.remove(lastReturned.key); 1183 lastReturned = null; 1184 } 1185 1186 } 1187 1188 1189 protected class KeyIterator extends HashIterator { 1190 protected Object returnValueOfNext() { return currentKey; } 1191 } 1192 1193 protected class ValueIterator extends HashIterator { 1194 protected Object returnValueOfNext() { return currentValue; } 1195 } 1196 1197 1198 1199 1212 1213 private synchronized void writeObject(java.io.ObjectOutputStream s) 1214 throws IOException { 1215 s.defaultWriteObject(); 1217 1218 s.writeInt(table.length); 1220 1221 s.writeInt(count); 1223 1224 for (int index = table.length-1; index >= 0; index--) { 1226 Entry entry = table[index]; 1227 1228 while (entry != null) { 1229 s.writeObject(entry.key); 1230 s.writeObject(entry.value); 1231 entry = entry.next; 1232 } 1233 } 1234 } 1235 1236 1241 private synchronized void readObject(java.io.ObjectInputStream s) 1242 throws IOException , ClassNotFoundException { 1243 s.defaultReadObject(); 1245 1246 int numBuckets = s.readInt(); 1248 table = new Entry[numBuckets]; 1249 1250 int size = s.readInt(); 1252 1253 for (int i=0; i<size; i++) { 1255 Object key = s.readObject(); 1256 Object value = s.readObject(); 1257 put(key, value); 1258 } 1259 } 1260 1261 1264 1265 public synchronized int capacity() { 1266 return table.length; 1267 } 1268 1269 1272 public float loadFactor() { 1273 return loadFactor; 1274 } 1275} 1276 | Popular Tags |