1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23 /* 24 * This file is available under and governed by the GNU General Public 25 * License version 2 only, as published by the Free Software Foundation. 26 * However, the following notice accompanied the original version of this 27 * file: 28 * 29 * Written by Doug Lea and Martin Buchholz with assistance from 30 * members of JCP JSR-166 Expert Group and released to the public 31 * domain, as explained at 32 * http://creativecommons.org/publicdomain/zero/1.0/ 33 * Other contributors include Andrew Wright, Jeffrey Hayes, 34 * Pat Fisher, Mike Judd. 35 */ 36 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.Collection; 40 import java.util.Collections; 41 import java.util.Enumeration; 42 import java.util.Iterator; 43 import java.util.Map; 44 import java.util.Random; 45 import java.util.Set; 46 import java.util.concurrent.ConcurrentHashMap; 47 48 import junit.framework.Test; 49 50 public class ConcurrentHashMapTest extends JSR166TestCase { main(String[] args)51 public static void main(String[] args) { 52 main(suite(), args); 53 } suite()54 public static Test suite() { 55 class Implementation implements MapImplementation { 56 public Class<?> klazz() { return ConcurrentHashMap.class; } 57 public Map emptyMap() { return new ConcurrentHashMap(); } 58 public Object makeKey(int i) { return i; } 59 public Object makeValue(int i) { return i; } 60 public boolean isConcurrent() { return true; } 61 public boolean permitsNullKeys() { return false; } 62 public boolean permitsNullValues() { return false; } 63 public boolean supportsSetValue() { return true; } 64 } 65 return newTestSuite( 66 ConcurrentHashMapTest.class, 67 MapTest.testSuite(new Implementation())); 68 } 69 70 /** 71 * Returns a new map from Integers 1-5 to Strings "A"-"E". 72 */ map5()73 private static ConcurrentHashMap<Integer, String> map5() { 74 ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>(5); 75 assertTrue(map.isEmpty()); 76 map.put(one, "A"); 77 map.put(two, "B"); 78 map.put(three, "C"); 79 map.put(four, "D"); 80 map.put(five, "E"); 81 assertFalse(map.isEmpty()); 82 assertEquals(5, map.size()); 83 return map; 84 } 85 86 // classes for testing Comparable fallbacks 87 static class BI implements Comparable<BI> { 88 private final int value; BI(int value)89 BI(int value) { this.value = value; } compareTo(BI other)90 public int compareTo(BI other) { 91 return Integer.compare(value, other.value); 92 } equals(Object x)93 public boolean equals(Object x) { 94 return (x instanceof BI) && ((BI)x).value == value; 95 } hashCode()96 public int hashCode() { return 42; } 97 } CI(int value)98 static class CI extends BI { CI(int value) { super(value); } } DI(int value)99 static class DI extends BI { DI(int value) { super(value); } } 100 101 static class BS implements Comparable<BS> { 102 private final String value; BS(String value)103 BS(String value) { this.value = value; } compareTo(BS other)104 public int compareTo(BS other) { 105 return value.compareTo(other.value); 106 } equals(Object x)107 public boolean equals(Object x) { 108 return (x instanceof BS) && value.equals(((BS)x).value); 109 } hashCode()110 public int hashCode() { return 42; } 111 } 112 113 static class LexicographicList<E extends Comparable<E>> extends ArrayList<E> 114 implements Comparable<LexicographicList<E>> { LexicographicList(Collection<E> c)115 LexicographicList(Collection<E> c) { super(c); } LexicographicList(E e)116 LexicographicList(E e) { super(Collections.singleton(e)); } compareTo(LexicographicList<E> other)117 public int compareTo(LexicographicList<E> other) { 118 int common = Math.min(size(), other.size()); 119 int r = 0; 120 for (int i = 0; i < common; i++) { 121 if ((r = get(i).compareTo(other.get(i))) != 0) 122 break; 123 } 124 if (r == 0) 125 r = Integer.compare(size(), other.size()); 126 return r; 127 } 128 private static final long serialVersionUID = 0; 129 } 130 131 static class CollidingObject { 132 final String value; CollidingObject(final String value)133 CollidingObject(final String value) { this.value = value; } hashCode()134 public int hashCode() { return this.value.hashCode() & 1; } equals(final Object obj)135 public boolean equals(final Object obj) { 136 return (obj instanceof CollidingObject) && ((CollidingObject)obj).value.equals(value); 137 } 138 } 139 140 static class ComparableCollidingObject extends CollidingObject implements Comparable<ComparableCollidingObject> { ComparableCollidingObject(final String value)141 ComparableCollidingObject(final String value) { super(value); } compareTo(final ComparableCollidingObject o)142 public int compareTo(final ComparableCollidingObject o) { 143 return value.compareTo(o.value); 144 } 145 } 146 147 /** 148 * Inserted elements that are subclasses of the same Comparable 149 * class are found. 150 */ testComparableFamily()151 public void testComparableFamily() { 152 int size = 500; // makes measured test run time -> 60ms 153 ConcurrentHashMap<BI, Boolean> m = new ConcurrentHashMap<>(); 154 for (int i = 0; i < size; i++) { 155 assertNull(m.put(new CI(i), true)); 156 } 157 for (int i = 0; i < size; i++) { 158 assertTrue(m.containsKey(new CI(i))); 159 assertTrue(m.containsKey(new DI(i))); 160 } 161 } 162 163 /** 164 * Elements of classes with erased generic type parameters based 165 * on Comparable can be inserted and found. 166 */ testGenericComparable()167 public void testGenericComparable() { 168 int size = 120; // makes measured test run time -> 60ms 169 ConcurrentHashMap<Object, Boolean> m = new ConcurrentHashMap<>(); 170 for (int i = 0; i < size; i++) { 171 BI bi = new BI(i); 172 BS bs = new BS(String.valueOf(i)); 173 LexicographicList<BI> bis = new LexicographicList<>(bi); 174 LexicographicList<BS> bss = new LexicographicList<>(bs); 175 assertNull(m.putIfAbsent(bis, true)); 176 assertTrue(m.containsKey(bis)); 177 if (m.putIfAbsent(bss, true) == null) 178 assertTrue(m.containsKey(bss)); 179 assertTrue(m.containsKey(bis)); 180 } 181 for (int i = 0; i < size; i++) { 182 assertTrue(m.containsKey(Collections.singletonList(new BI(i)))); 183 } 184 } 185 186 /** 187 * Elements of non-comparable classes equal to those of classes 188 * with erased generic type parameters based on Comparable can be 189 * inserted and found. 190 */ testGenericComparable2()191 public void testGenericComparable2() { 192 int size = 500; // makes measured test run time -> 60ms 193 ConcurrentHashMap<Object, Boolean> m = new ConcurrentHashMap<>(); 194 for (int i = 0; i < size; i++) { 195 m.put(Collections.singletonList(new BI(i)), true); 196 } 197 198 for (int i = 0; i < size; i++) { 199 LexicographicList<BI> bis = new LexicographicList<>(new BI(i)); 200 assertTrue(m.containsKey(bis)); 201 } 202 } 203 204 /** 205 * Mixtures of instances of comparable and non-comparable classes 206 * can be inserted and found. 207 */ testMixedComparable()208 public void testMixedComparable() { 209 int size = 1200; // makes measured test run time -> 35ms 210 ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>(); 211 Random rng = new Random(); 212 for (int i = 0; i < size; i++) { 213 Object x; 214 switch (rng.nextInt(4)) { 215 case 0: 216 x = new Object(); 217 break; 218 case 1: 219 x = new CollidingObject(Integer.toString(i)); 220 break; 221 default: 222 x = new ComparableCollidingObject(Integer.toString(i)); 223 } 224 assertNull(map.put(x, x)); 225 } 226 int count = 0; 227 for (Object k : map.keySet()) { 228 assertEquals(map.get(k), k); 229 ++count; 230 } 231 assertEquals(count, size); 232 assertEquals(map.size(), size); 233 for (Object k : map.keySet()) { 234 assertEquals(map.put(k, k), k); 235 } 236 } 237 238 /** 239 * clear removes all pairs 240 */ testClear()241 public void testClear() { 242 ConcurrentHashMap map = map5(); 243 map.clear(); 244 assertEquals(0, map.size()); 245 } 246 247 /** 248 * Maps with same contents are equal 249 */ testEquals()250 public void testEquals() { 251 ConcurrentHashMap map1 = map5(); 252 ConcurrentHashMap map2 = map5(); 253 assertEquals(map1, map2); 254 assertEquals(map2, map1); 255 map1.clear(); 256 assertFalse(map1.equals(map2)); 257 assertFalse(map2.equals(map1)); 258 } 259 260 /** 261 * hashCode() equals sum of each key.hashCode ^ value.hashCode 262 */ testHashCode()263 public void testHashCode() { 264 ConcurrentHashMap<Integer,String> map = map5(); 265 int sum = 0; 266 for (Map.Entry<Integer,String> e : map.entrySet()) 267 sum += e.getKey().hashCode() ^ e.getValue().hashCode(); 268 assertEquals(sum, map.hashCode()); 269 } 270 271 /** 272 * contains returns true for contained value 273 */ testContains()274 public void testContains() { 275 ConcurrentHashMap map = map5(); 276 assertTrue(map.contains("A")); 277 assertFalse(map.contains("Z")); 278 } 279 280 /** 281 * containsKey returns true for contained key 282 */ testContainsKey()283 public void testContainsKey() { 284 ConcurrentHashMap map = map5(); 285 assertTrue(map.containsKey(one)); 286 assertFalse(map.containsKey(zero)); 287 } 288 289 /** 290 * containsValue returns true for held values 291 */ testContainsValue()292 public void testContainsValue() { 293 ConcurrentHashMap map = map5(); 294 assertTrue(map.containsValue("A")); 295 assertFalse(map.containsValue("Z")); 296 } 297 298 /** 299 * enumeration returns an enumeration containing the correct 300 * elements 301 */ testEnumeration()302 public void testEnumeration() { 303 ConcurrentHashMap map = map5(); 304 Enumeration e = map.elements(); 305 int count = 0; 306 while (e.hasMoreElements()) { 307 count++; 308 e.nextElement(); 309 } 310 assertEquals(5, count); 311 } 312 313 /** 314 * get returns the correct element at the given key, 315 * or null if not present 316 */ testGet()317 public void testGet() { 318 ConcurrentHashMap map = map5(); 319 assertEquals("A", (String)map.get(one)); 320 ConcurrentHashMap empty = new ConcurrentHashMap(); 321 assertNull(map.get("anything")); 322 assertNull(empty.get("anything")); 323 } 324 325 /** 326 * isEmpty is true of empty map and false for non-empty 327 */ testIsEmpty()328 public void testIsEmpty() { 329 ConcurrentHashMap empty = new ConcurrentHashMap(); 330 ConcurrentHashMap map = map5(); 331 assertTrue(empty.isEmpty()); 332 assertFalse(map.isEmpty()); 333 } 334 335 /** 336 * keys returns an enumeration containing all the keys from the map 337 */ testKeys()338 public void testKeys() { 339 ConcurrentHashMap map = map5(); 340 Enumeration e = map.keys(); 341 int count = 0; 342 while (e.hasMoreElements()) { 343 count++; 344 e.nextElement(); 345 } 346 assertEquals(5, count); 347 } 348 349 /** 350 * keySet returns a Set containing all the keys 351 */ testKeySet()352 public void testKeySet() { 353 ConcurrentHashMap map = map5(); 354 Set s = map.keySet(); 355 assertEquals(5, s.size()); 356 assertTrue(s.contains(one)); 357 assertTrue(s.contains(two)); 358 assertTrue(s.contains(three)); 359 assertTrue(s.contains(four)); 360 assertTrue(s.contains(five)); 361 } 362 363 /** 364 * Test keySet().removeAll on empty map 365 */ testKeySet_empty_removeAll()366 public void testKeySet_empty_removeAll() { 367 ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>(); 368 Set<Integer> set = map.keySet(); 369 set.removeAll(Collections.emptyList()); 370 assertTrue(map.isEmpty()); 371 assertTrue(set.isEmpty()); 372 // following is test for JDK-8163353 373 set.removeAll(Collections.emptySet()); 374 assertTrue(map.isEmpty()); 375 assertTrue(set.isEmpty()); 376 } 377 378 /** 379 * keySet.toArray returns contains all keys 380 */ testKeySetToArray()381 public void testKeySetToArray() { 382 ConcurrentHashMap map = map5(); 383 Set s = map.keySet(); 384 Object[] ar = s.toArray(); 385 assertTrue(s.containsAll(Arrays.asList(ar))); 386 assertEquals(5, ar.length); 387 ar[0] = m10; 388 assertFalse(s.containsAll(Arrays.asList(ar))); 389 } 390 391 /** 392 * Values.toArray contains all values 393 */ testValuesToArray()394 public void testValuesToArray() { 395 ConcurrentHashMap map = map5(); 396 Collection v = map.values(); 397 Object[] ar = v.toArray(); 398 ArrayList s = new ArrayList(Arrays.asList(ar)); 399 assertEquals(5, ar.length); 400 assertTrue(s.contains("A")); 401 assertTrue(s.contains("B")); 402 assertTrue(s.contains("C")); 403 assertTrue(s.contains("D")); 404 assertTrue(s.contains("E")); 405 } 406 407 /** 408 * entrySet.toArray contains all entries 409 */ testEntrySetToArray()410 public void testEntrySetToArray() { 411 ConcurrentHashMap map = map5(); 412 Set s = map.entrySet(); 413 Object[] ar = s.toArray(); 414 assertEquals(5, ar.length); 415 for (int i = 0; i < 5; ++i) { 416 assertTrue(map.containsKey(((Map.Entry)(ar[i])).getKey())); 417 assertTrue(map.containsValue(((Map.Entry)(ar[i])).getValue())); 418 } 419 } 420 421 /** 422 * values collection contains all values 423 */ testValues()424 public void testValues() { 425 ConcurrentHashMap map = map5(); 426 Collection s = map.values(); 427 assertEquals(5, s.size()); 428 assertTrue(s.contains("A")); 429 assertTrue(s.contains("B")); 430 assertTrue(s.contains("C")); 431 assertTrue(s.contains("D")); 432 assertTrue(s.contains("E")); 433 } 434 435 /** 436 * entrySet contains all pairs 437 */ testEntrySet()438 public void testEntrySet() { 439 ConcurrentHashMap map = map5(); 440 Set s = map.entrySet(); 441 assertEquals(5, s.size()); 442 Iterator it = s.iterator(); 443 while (it.hasNext()) { 444 Map.Entry e = (Map.Entry) it.next(); 445 assertTrue( 446 (e.getKey().equals(one) && e.getValue().equals("A")) || 447 (e.getKey().equals(two) && e.getValue().equals("B")) || 448 (e.getKey().equals(three) && e.getValue().equals("C")) || 449 (e.getKey().equals(four) && e.getValue().equals("D")) || 450 (e.getKey().equals(five) && e.getValue().equals("E"))); 451 } 452 } 453 454 /** 455 * putAll adds all key-value pairs from the given map 456 */ testPutAll()457 public void testPutAll() { 458 ConcurrentHashMap empty = new ConcurrentHashMap(); 459 ConcurrentHashMap map = map5(); 460 empty.putAll(map); 461 assertEquals(5, empty.size()); 462 assertTrue(empty.containsKey(one)); 463 assertTrue(empty.containsKey(two)); 464 assertTrue(empty.containsKey(three)); 465 assertTrue(empty.containsKey(four)); 466 assertTrue(empty.containsKey(five)); 467 } 468 469 /** 470 * putIfAbsent works when the given key is not present 471 */ testPutIfAbsent()472 public void testPutIfAbsent() { 473 ConcurrentHashMap map = map5(); 474 map.putIfAbsent(six, "Z"); 475 assertTrue(map.containsKey(six)); 476 } 477 478 /** 479 * putIfAbsent does not add the pair if the key is already present 480 */ testPutIfAbsent2()481 public void testPutIfAbsent2() { 482 ConcurrentHashMap map = map5(); 483 assertEquals("A", map.putIfAbsent(one, "Z")); 484 } 485 486 /** 487 * replace fails when the given key is not present 488 */ testReplace()489 public void testReplace() { 490 ConcurrentHashMap map = map5(); 491 assertNull(map.replace(six, "Z")); 492 assertFalse(map.containsKey(six)); 493 } 494 495 /** 496 * replace succeeds if the key is already present 497 */ testReplace2()498 public void testReplace2() { 499 ConcurrentHashMap map = map5(); 500 assertNotNull(map.replace(one, "Z")); 501 assertEquals("Z", map.get(one)); 502 } 503 504 /** 505 * replace value fails when the given key not mapped to expected value 506 */ testReplaceValue()507 public void testReplaceValue() { 508 ConcurrentHashMap map = map5(); 509 assertEquals("A", map.get(one)); 510 assertFalse(map.replace(one, "Z", "Z")); 511 assertEquals("A", map.get(one)); 512 } 513 514 /** 515 * replace value succeeds when the given key mapped to expected value 516 */ testReplaceValue2()517 public void testReplaceValue2() { 518 ConcurrentHashMap map = map5(); 519 assertEquals("A", map.get(one)); 520 assertTrue(map.replace(one, "A", "Z")); 521 assertEquals("Z", map.get(one)); 522 } 523 524 /** 525 * remove removes the correct key-value pair from the map 526 */ testRemove()527 public void testRemove() { 528 ConcurrentHashMap map = map5(); 529 map.remove(five); 530 assertEquals(4, map.size()); 531 assertFalse(map.containsKey(five)); 532 } 533 534 /** 535 * remove(key,value) removes only if pair present 536 */ testRemove2()537 public void testRemove2() { 538 ConcurrentHashMap map = map5(); 539 map.remove(five, "E"); 540 assertEquals(4, map.size()); 541 assertFalse(map.containsKey(five)); 542 map.remove(four, "A"); 543 assertEquals(4, map.size()); 544 assertTrue(map.containsKey(four)); 545 } 546 547 /** 548 * size returns the correct values 549 */ testSize()550 public void testSize() { 551 ConcurrentHashMap map = map5(); 552 ConcurrentHashMap empty = new ConcurrentHashMap(); 553 assertEquals(0, empty.size()); 554 assertEquals(5, map.size()); 555 } 556 557 /** 558 * toString contains toString of elements 559 */ testToString()560 public void testToString() { 561 ConcurrentHashMap map = map5(); 562 String s = map.toString(); 563 for (int i = 1; i <= 5; ++i) { 564 assertTrue(s.contains(String.valueOf(i))); 565 } 566 } 567 568 // Exception tests 569 570 /** 571 * Cannot create with only negative capacity 572 */ testConstructor1()573 public void testConstructor1() { 574 try { 575 new ConcurrentHashMap(-1); 576 shouldThrow(); 577 } catch (IllegalArgumentException success) {} 578 } 579 580 /** 581 * Constructor (initialCapacity, loadFactor) throws 582 * IllegalArgumentException if either argument is negative 583 */ testConstructor2()584 public void testConstructor2() { 585 try { 586 new ConcurrentHashMap(-1, .75f); 587 shouldThrow(); 588 } catch (IllegalArgumentException success) {} 589 590 try { 591 new ConcurrentHashMap(16, -1); 592 shouldThrow(); 593 } catch (IllegalArgumentException success) {} 594 } 595 596 /** 597 * Constructor (initialCapacity, loadFactor, concurrencyLevel) 598 * throws IllegalArgumentException if any argument is negative 599 */ testConstructor3()600 public void testConstructor3() { 601 try { 602 new ConcurrentHashMap(-1, .75f, 1); 603 shouldThrow(); 604 } catch (IllegalArgumentException success) {} 605 606 try { 607 new ConcurrentHashMap(16, -1, 1); 608 shouldThrow(); 609 } catch (IllegalArgumentException success) {} 610 611 try { 612 new ConcurrentHashMap(16, .75f, -1); 613 shouldThrow(); 614 } catch (IllegalArgumentException success) {} 615 } 616 617 /** 618 * ConcurrentHashMap(map) throws NullPointerException if the given 619 * map is null 620 */ testConstructor4()621 public void testConstructor4() { 622 try { 623 new ConcurrentHashMap(null); 624 shouldThrow(); 625 } catch (NullPointerException success) {} 626 } 627 628 /** 629 * ConcurrentHashMap(map) creates a new map with the same mappings 630 * as the given map 631 */ testConstructor5()632 public void testConstructor5() { 633 ConcurrentHashMap map1 = map5(); 634 ConcurrentHashMap map2 = new ConcurrentHashMap(map5()); 635 assertTrue(map2.equals(map1)); 636 map2.put(one, "F"); 637 assertFalse(map2.equals(map1)); 638 } 639 640 /** 641 * get(null) throws NPE 642 */ testGet_NullPointerException()643 public void testGet_NullPointerException() { 644 ConcurrentHashMap c = new ConcurrentHashMap(5); 645 try { 646 c.get(null); 647 shouldThrow(); 648 } catch (NullPointerException success) {} 649 } 650 651 /** 652 * containsKey(null) throws NPE 653 */ testContainsKey_NullPointerException()654 public void testContainsKey_NullPointerException() { 655 ConcurrentHashMap c = new ConcurrentHashMap(5); 656 try { 657 c.containsKey(null); 658 shouldThrow(); 659 } catch (NullPointerException success) {} 660 } 661 662 /** 663 * containsValue(null) throws NPE 664 */ testContainsValue_NullPointerException()665 public void testContainsValue_NullPointerException() { 666 ConcurrentHashMap c = new ConcurrentHashMap(5); 667 try { 668 c.containsValue(null); 669 shouldThrow(); 670 } catch (NullPointerException success) {} 671 } 672 673 /** 674 * contains(null) throws NPE 675 */ testContains_NullPointerException()676 public void testContains_NullPointerException() { 677 ConcurrentHashMap c = new ConcurrentHashMap(5); 678 try { 679 c.contains(null); 680 shouldThrow(); 681 } catch (NullPointerException success) {} 682 } 683 684 /** 685 * put(null,x) throws NPE 686 */ testPut1_NullPointerException()687 public void testPut1_NullPointerException() { 688 ConcurrentHashMap c = new ConcurrentHashMap(5); 689 try { 690 c.put(null, "whatever"); 691 shouldThrow(); 692 } catch (NullPointerException success) {} 693 } 694 695 /** 696 * put(x, null) throws NPE 697 */ testPut2_NullPointerException()698 public void testPut2_NullPointerException() { 699 ConcurrentHashMap c = new ConcurrentHashMap(5); 700 try { 701 c.put("whatever", null); 702 shouldThrow(); 703 } catch (NullPointerException success) {} 704 } 705 706 /** 707 * putIfAbsent(null, x) throws NPE 708 */ testPutIfAbsent1_NullPointerException()709 public void testPutIfAbsent1_NullPointerException() { 710 ConcurrentHashMap c = new ConcurrentHashMap(5); 711 try { 712 c.putIfAbsent(null, "whatever"); 713 shouldThrow(); 714 } catch (NullPointerException success) {} 715 } 716 717 /** 718 * replace(null, x) throws NPE 719 */ testReplace_NullPointerException()720 public void testReplace_NullPointerException() { 721 ConcurrentHashMap c = new ConcurrentHashMap(5); 722 try { 723 c.replace(null, "whatever"); 724 shouldThrow(); 725 } catch (NullPointerException success) {} 726 } 727 728 /** 729 * replace(null, x, y) throws NPE 730 */ testReplaceValue_NullPointerException()731 public void testReplaceValue_NullPointerException() { 732 ConcurrentHashMap c = new ConcurrentHashMap(5); 733 try { 734 c.replace(null, one, "whatever"); 735 shouldThrow(); 736 } catch (NullPointerException success) {} 737 } 738 739 /** 740 * putIfAbsent(x, null) throws NPE 741 */ testPutIfAbsent2_NullPointerException()742 public void testPutIfAbsent2_NullPointerException() { 743 ConcurrentHashMap c = new ConcurrentHashMap(5); 744 try { 745 c.putIfAbsent("whatever", null); 746 shouldThrow(); 747 } catch (NullPointerException success) {} 748 } 749 750 /** 751 * replace(x, null) throws NPE 752 */ testReplace2_NullPointerException()753 public void testReplace2_NullPointerException() { 754 ConcurrentHashMap c = new ConcurrentHashMap(5); 755 try { 756 c.replace("whatever", null); 757 shouldThrow(); 758 } catch (NullPointerException success) {} 759 } 760 761 /** 762 * replace(x, null, y) throws NPE 763 */ testReplaceValue2_NullPointerException()764 public void testReplaceValue2_NullPointerException() { 765 ConcurrentHashMap c = new ConcurrentHashMap(5); 766 try { 767 c.replace("whatever", null, "A"); 768 shouldThrow(); 769 } catch (NullPointerException success) {} 770 } 771 772 /** 773 * replace(x, y, null) throws NPE 774 */ testReplaceValue3_NullPointerException()775 public void testReplaceValue3_NullPointerException() { 776 ConcurrentHashMap c = new ConcurrentHashMap(5); 777 try { 778 c.replace("whatever", one, null); 779 shouldThrow(); 780 } catch (NullPointerException success) {} 781 } 782 783 /** 784 * remove(null) throws NPE 785 */ testRemove1_NullPointerException()786 public void testRemove1_NullPointerException() { 787 ConcurrentHashMap c = new ConcurrentHashMap(5); 788 c.put("sadsdf", "asdads"); 789 try { 790 c.remove(null); 791 shouldThrow(); 792 } catch (NullPointerException success) {} 793 } 794 795 /** 796 * remove(null, x) throws NPE 797 */ testRemove2_NullPointerException()798 public void testRemove2_NullPointerException() { 799 ConcurrentHashMap c = new ConcurrentHashMap(5); 800 c.put("sadsdf", "asdads"); 801 try { 802 c.remove(null, "whatever"); 803 shouldThrow(); 804 } catch (NullPointerException success) {} 805 } 806 807 /** 808 * remove(x, null) returns false 809 */ testRemove3()810 public void testRemove3() { 811 ConcurrentHashMap c = new ConcurrentHashMap(5); 812 c.put("sadsdf", "asdads"); 813 assertFalse(c.remove("sadsdf", null)); 814 } 815 816 /** 817 * A deserialized/reserialized map equals original 818 */ testSerialization()819 public void testSerialization() throws Exception { 820 Map x = map5(); 821 Map y = serialClone(x); 822 823 assertNotSame(x, y); 824 assertEquals(x.size(), y.size()); 825 assertEquals(x, y); 826 assertEquals(y, x); 827 } 828 829 /** 830 * SetValue of an EntrySet entry sets value in the map. 831 */ testSetValueWriteThrough()832 public void testSetValueWriteThrough() { 833 // Adapted from a bug report by Eric Zoerner 834 ConcurrentHashMap map = new ConcurrentHashMap(2, 5.0f, 1); 835 assertTrue(map.isEmpty()); 836 for (int i = 0; i < 20; i++) 837 map.put(new Integer(i), new Integer(i)); 838 assertFalse(map.isEmpty()); 839 Map.Entry entry1 = (Map.Entry)map.entrySet().iterator().next(); 840 // Unless it happens to be first (in which case remainder of 841 // test is skipped), remove a possibly-colliding key from map 842 // which, under some implementations, may cause entry1 to be 843 // cloned in map 844 if (!entry1.getKey().equals(new Integer(16))) { 845 map.remove(new Integer(16)); 846 entry1.setValue("XYZ"); 847 assertTrue(map.containsValue("XYZ")); // fails if write-through broken 848 } 849 } 850 851 /** 852 * Tests performance of removeAll when the other collection is much smaller. 853 * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testRemoveAll_performance -Djsr166.expensiveTests=true tck 854 */ testRemoveAll_performance()855 public void testRemoveAll_performance() { 856 final int mapSize = expensiveTests ? 1_000_000 : 100; 857 final int iterations = expensiveTests ? 500 : 2; 858 final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>(); 859 for (int i = 0; i < mapSize; i++) 860 map.put(i, i); 861 Set<Integer> keySet = map.keySet(); 862 Collection<Integer> removeMe = Arrays.asList(new Integer[] { -99, -86 }); 863 for (int i = 0; i < iterations; i++) 864 assertFalse(keySet.removeAll(removeMe)); 865 assertEquals(mapSize, map.size()); 866 } 867 testReentrantComputeIfAbsent()868 public void testReentrantComputeIfAbsent() { 869 ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>(16); 870 try { 871 for (int i = 0; i < 100; i++) { // force a resize 872 map.computeIfAbsent(i, key -> findValue(map, key)); 873 } 874 fail("recursive computeIfAbsent should throw IllegalStateException"); 875 } catch (IllegalStateException success) {} 876 } 877 findValue(ConcurrentHashMap<Integer, Integer> map, Integer key)878 private Integer findValue(ConcurrentHashMap<Integer, Integer> map, 879 Integer key) { 880 return (key % 5 == 0) ? key : 881 map.computeIfAbsent(key + 1, k -> findValue(map, k)); 882 } 883 884 } 885