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 (); 872 int hash = hash(key); 873 return segmentFor(hash).put(key, hash, value, true); 874 } 875 876 877 885 public void putAll(Map<? extends K, ? extends V> t) { 886 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> it = (Iterator<? extends Map.Entry<? extends K, ? extends V>>) t.entrySet().iterator(); it.hasNext(); ) { 887 Entry<? extends K, ? extends V> e = it.next(); 888 put(e.getKey(), e.getValue()); 889 } 890 } 891 892 902 public V remove(Object key) { 903 int hash = hash(key); 904 return segmentFor(hash).remove(key, hash, null); 905 } 906 907 923 public boolean remove(Object key, Object value) { 924 int hash = hash(key); 925 return segmentFor(hash).remove(key, hash, value) != null; 926 } 927 928 929 946 public boolean replace(K key, V oldValue, V newValue) { 947 if (oldValue == null || newValue == null) 948 throw new NullPointerException (); 949 int hash = hash(key); 950 return segmentFor(hash).replace(key, hash, oldValue, newValue); 951 } 952 953 969 public V replace(K key, V value) { 970 if (value == null) 971 throw new NullPointerException (); 972 int hash = hash(key); 973 return segmentFor(hash).replace(key, hash, value); 974 } 975 976 977 980 public void clear() { 981 for (int i = 0; i < segments.length; ++i) 982 segments[i].clear(); 983 } 984 985 1001 public Set<K> keySet() { 1002 Set<K> ks = keySet; 1003 return (ks != null) ? ks : (keySet = new KeySet()); 1004 } 1005 1006 1007 1023 public Collection<V> values() { 1024 Collection<V> vs = values; 1025 return (vs != null) ? vs : (values = new Values()); 1026 } 1027 1028 1029 1046 public Set<Map.Entry<K,V>> entrySet() { 1047 Set<Map.Entry<K,V>> es = entrySet; 1048 return (es != null) ? es : (entrySet = (Set<Map.Entry<K,V>>) (Set) new EntrySet()); 1049 } 1050 1051 1052 1058 public Enumeration<K> keys() { 1059 return new KeyIterator(); 1060 } 1061 1062 1068 public Enumeration<V> elements() { 1069 return new ValueIterator(); 1070 } 1071 1072 1073 1074 abstract class HashIterator { 1075 int nextSegmentIndex; 1076 int nextTableIndex; 1077 HashEntry[] currentTable; 1078 HashEntry<K, V> nextEntry; 1079 HashEntry<K, V> lastReturned; 1080 1081 HashIterator() { 1082 nextSegmentIndex = segments.length - 1; 1083 nextTableIndex = -1; 1084 advance(); 1085 } 1086 1087 public boolean hasMoreElements() { return hasNext(); } 1088 1089 final void advance() { 1090 if (nextEntry != null && (nextEntry = nextEntry.next) != null) 1091 return; 1092 1093 while (nextTableIndex >= 0) { 1094 if ( (nextEntry = (HashEntry<K,V>)currentTable[nextTableIndex--]) != null) 1095 return; 1096 } 1097 1098 while (nextSegmentIndex >= 0) { 1099 Segment<K,V> seg = (Segment<K,V>)segments[nextSegmentIndex--]; 1100 if (seg.count != 0) { 1101 currentTable = seg.table; 1102 for (int j = currentTable.length - 1; j >= 0; --j) { 1103 if ( (nextEntry = (HashEntry<K,V>)currentTable[j]) != null) { 1104 nextTableIndex = j - 1; 1105 return; 1106 } 1107 } 1108 } 1109 } 1110 } 1111 1112 public boolean hasNext() { return nextEntry != null; } 1113 1114 HashEntry<K,V> nextEntry() { 1115 if (nextEntry == null) 1116 throw new NoSuchElementException(); 1117 lastReturned = nextEntry; 1118 advance(); 1119 return lastReturned; 1120 } 1121 1122 public void remove() { 1123 if (lastReturned == null) 1124 throw new IllegalStateException (); 1125 ConcurrentHashMap.this.remove(lastReturned.key); 1126 lastReturned = null; 1127 } 1128 } 1129 1130 final class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> { 1131 public K next() { return super.nextEntry().key; } 1132 public K nextElement() { return super.nextEntry().key; } 1133 } 1134 1135 final class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> { 1136 public V next() { return super.nextEntry().value; } 1137 public V nextElement() { return super.nextEntry().value; } 1138 } 1139 1140 1141 1142 1148 final class EntryIterator extends HashIterator implements Map.Entry<K,V>, Iterator<Entry<K,V>> { 1149 public Map.Entry<K,V> next() { 1150 nextEntry(); 1151 return this; 1152 } 1153 1154 public K getKey() { 1155 if (lastReturned == null) 1156 throw new IllegalStateException ("Entry was removed"); 1157 return lastReturned.key; 1158 } 1159 1160 public V getValue() { 1161 if (lastReturned == null) 1162 throw new IllegalStateException ("Entry was removed"); 1163 return ConcurrentHashMap.this.get(lastReturned.key); 1164 } 1165 1166 public V setValue(V value) { 1167 if (lastReturned == null) 1168 throw new IllegalStateException ("Entry was removed"); 1169 return ConcurrentHashMap.this.put(lastReturned.key, value); 1170 } 1171 1172 public boolean equals(Object o) { 1173 if (lastReturned == null) 1175 return super.equals(o); 1176 if (!(o instanceof Map.Entry)) 1177 return false; 1178 Map.Entry e = (Map.Entry)o; 1179 return eq(getKey(), e.getKey()) && eq(getValue(), e.getValue()); 1180 } 1181 1182 public int hashCode() { 1183 if (lastReturned == null) 1185 return super.hashCode(); 1186 1187 Object k = getKey(); 1188 Object v = getValue(); 1189 return ((k == null) ? 0 : k.hashCode()) ^ 1190 ((v == null) ? 0 : v.hashCode()); 1191 } 1192 1193 public String toString() { 1194 if (lastReturned == null) 1196 return super.toString(); 1197 else 1198 return getKey() + "=" + getValue(); 1199 } 1200 1201 boolean eq(Object o1, Object o2) { 1202 return (o1 == null ? o2 == null : o1.equals(o2)); 1203 } 1204 1205 } 1206 1207 final class KeySet extends AbstractSet<K> { 1208 public Iterator<K> iterator() { 1209 return new KeyIterator(); 1210 } 1211 public int size() { 1212 return ConcurrentHashMap.this.size(); 1213 } 1214 public boolean contains(Object o) { 1215 return ConcurrentHashMap.this.containsKey(o); 1216 } 1217 public boolean remove(Object o) { 1218 return ConcurrentHashMap.this.remove(o) != null; 1219 } 1220 public void clear() { 1221 ConcurrentHashMap.this.clear(); 1222 } 1223 public Object [] toArray() { 1224 Collection<K> c = new ArrayList<K>(); 1225 for (Iterator<K> i = iterator(); i.hasNext(); ) 1226 c.add(i.next()); 1227 return c.toArray(); 1228 } 1229 public <T> T[] toArray(T[] a) { 1230 Collection<K> c = new ArrayList<K>(); 1231 for (Iterator<K> i = iterator(); i.hasNext(); ) 1232 c.add(i.next()); 1233 return c.toArray(a); 1234 } 1235 } 1236 1237 final class Values extends AbstractCollection<V> { 1238 public Iterator<V> iterator() { 1239 return new ValueIterator(); 1240 } 1241 public int size() { 1242 return ConcurrentHashMap.this.size(); 1243 } 1244 public boolean contains(Object o) { 1245 return ConcurrentHashMap.this.containsValue(o); 1246 } 1247 public void clear() { 1248 ConcurrentHashMap.this.clear(); 1249 } 1250 public Object [] toArray() { 1251 Collection<V> c = new ArrayList<V>(); 1252 for (Iterator<V> i = iterator(); i.hasNext(); ) 1253 c.add(i.next()); 1254 return c.toArray(); 1255 } 1256 public <T> T[] toArray(T[] a) { 1257 Collection<V> c = new ArrayList<V>(); 1258 for (Iterator<V> i = iterator(); i.hasNext(); ) 1259 c.add(i.next()); 1260 return c.toArray(a); 1261 } 1262 } 1263 1264 final class EntrySet extends AbstractSet<Map.Entry<K,V>> { 1265 public Iterator<Map.Entry<K,V>> iterator() { 1266 return new EntryIterator(); 1267 } 1268 public boolean contains(Object o) { 1269 if (!(o instanceof Map.Entry)) 1270 return false; 1271 Map.Entry<K,V> e = (Map.Entry<K,V>)o; 1272 V v = ConcurrentHashMap.this.get(e.getKey()); 1273 return v != null && v.equals(e.getValue()); 1274 } 1275 public boolean remove(Object o) { 1276 if (!(o instanceof Map.Entry)) 1277 return false; 1278 Map.Entry<K,V> e = (Map.Entry<K,V>)o; 1279 return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); 1280 } 1281 public int size() { 1282 return ConcurrentHashMap.this.size(); 1283 } 1284 public void clear() { 1285 ConcurrentHashMap.this.clear(); 1286 } 1287 public Object [] toArray() { 1288 Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); 1291 for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) 1292 c.add(new SimpleEntry<K,V>(i.next())); 1293 return c.toArray(); 1294 } 1295 public <T> T[] toArray(T[] a) { 1296 Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); 1297 for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) 1298 c.add(new SimpleEntry<K,V>(i.next())); 1299 return c.toArray(a); 1300 } 1301 1302 } 1303 1304 1308 static final class SimpleEntry<K,V> implements Entry<K,V> { 1309 K key; 1310 V value; 1311 1312 public SimpleEntry(K key, V value) { 1313 this.key = key; 1314 this.value = value; 1315 } 1316 1317 public SimpleEntry(Entry<K,V> e) { 1318 this.key = e.getKey(); 1319 this.value = e.getValue(); 1320 } 1321 1322 public K getKey() { 1323 return key; 1324 } 1325 1326 public V getValue() { 1327 return value; 1328 } 1329 1330 public V setValue(V value) { 1331 V oldValue = this.value; 1332 this.value = value; 1333 return oldValue; 1334 } 1335 1336 public boolean equals(Object o) { 1337 if (!(o instanceof Map.Entry)) 1338 return false; 1339 Map.Entry e = (Map.Entry)o; 1340 return eq(key, e.getKey()) && eq(value, e.getValue()); 1341 } 1342 1343 public int hashCode() { 1344 return ((key == null) ? 0 : key.hashCode()) ^ 1345 ((value == null) ? 0 : value.hashCode()); 1346 } 1347 1348 public String toString() { 1349 return key + "=" + value; 1350 } 1351 1352 static boolean eq(Object o1, Object o2) { 1353 return (o1 == null ? o2 == null : o1.equals(o2)); 1354 } 1355 } 1356 1357 1358 1359 1369 private void writeObject(java.io.ObjectOutputStream s) throws IOException { 1370 s.defaultWriteObject(); 1371 1372 for (int k = 0; k < segments.length; ++k) { 1373 Segment<K,V> seg = (Segment<K,V>)segments[k]; 1374 seg.lock(); 1375 try { 1376 HashEntry[] tab = seg.table; 1377 for (int i = 0; i < tab.length; ++i) { 1378 for (HashEntry<K,V> e = (HashEntry<K,V>)tab[i]; e != null; e = e.next) { 1379 s.writeObject(e.key); 1380 s.writeObject(e.value); 1381 } 1382 } 1383 } finally { 1384 seg.unlock(); 1385 } 1386 } 1387 s.writeObject(null); 1388 s.writeObject(null); 1389 } 1390 1391 1397 private void readObject(java.io.ObjectInputStream s) 1398 throws IOException , ClassNotFoundException { 1399 s.defaultReadObject(); 1400 1401 for (int i = 0; i < segments.length; ++i) { 1403 segments[i].setTable(new HashEntry[1]); 1404 } 1405 1406 for (;;) { 1408 K key = (K) s.readObject(); 1409 V value = (V) s.readObject(); 1410 if (key == null) 1411 break; 1412 put(key, value); 1413 } 1414 } 1415} 1416 | Popular Tags |