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