--- jsr166/src/test/tck/ConcurrentHashMapTest.java 2016/08/22 18:38:28 1.50 +++ jsr166/src/test/tck/ConcurrentHashMapTest.java 2019/09/29 20:40:48 1.62 @@ -1,6 +1,7 @@ /* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ * Other contributors include Andrew Wright, Jeffrey Hayes, * Pat Fisher, Mike Judd. @@ -16,25 +17,32 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import junit.framework.Test; -import junit.framework.TestSuite; public class ConcurrentHashMapTest extends JSR166TestCase { public static void main(String[] args) { main(suite(), args); } public static Test suite() { - return new TestSuite(ConcurrentHashMapTest.class); + class Implementation implements MapImplementation { + public Class klazz() { return ConcurrentHashMap.class; } + public Map emptyMap() { return new ConcurrentHashMap(); } + public boolean isConcurrent() { return true; } + public boolean permitsNullKeys() { return false; } + public boolean permitsNullValues() { return false; } + public boolean supportsSetValue() { return true; } + } + return newTestSuite( + ConcurrentHashMapTest.class, + MapTest.testSuite(new Implementation())); } /** * Returns a new map from Integers 1-5 to Strings "A"-"E". */ private static ConcurrentHashMap map5() { - ConcurrentHashMap map = new ConcurrentHashMap(5); + ConcurrentHashMap map = new ConcurrentHashMap<>(5); assertTrue(map.isEmpty()); map.put(one, "A"); map.put(two, "B"); @@ -46,17 +54,12 @@ public class ConcurrentHashMapTest exten return map; } - /** Re-implement Integer.compare for old java versions */ - static int compare(int x, int y) { - return (x < y) ? -1 : (x > y) ? 1 : 0; - } - // classes for testing Comparable fallbacks static class BI implements Comparable { private final int value; BI(int value) { this.value = value; } public int compareTo(BI other) { - return compare(value, other.value); + return Integer.compare(value, other.value); } public boolean equals(Object x) { return (x instanceof BI) && ((BI)x).value == value; @@ -90,7 +93,7 @@ public class ConcurrentHashMapTest exten break; } if (r == 0) - r = compare(size(), other.size()); + r = Integer.compare(size(), other.size()); return r; } private static final long serialVersionUID = 0; @@ -118,10 +121,9 @@ public class ConcurrentHashMapTest exten */ public void testComparableFamily() { int size = 500; // makes measured test run time -> 60ms - ConcurrentHashMap m = - new ConcurrentHashMap(); + ConcurrentHashMap m = new ConcurrentHashMap<>(); for (int i = 0; i < size; i++) { - assertTrue(m.put(new CI(i), true) == null); + assertNull(m.put(new CI(i), true)); } for (int i = 0; i < size; i++) { assertTrue(m.containsKey(new CI(i))); @@ -135,14 +137,13 @@ public class ConcurrentHashMapTest exten */ public void testGenericComparable() { int size = 120; // makes measured test run time -> 60ms - ConcurrentHashMap m = - new ConcurrentHashMap(); + ConcurrentHashMap m = new ConcurrentHashMap<>(); for (int i = 0; i < size; i++) { BI bi = new BI(i); BS bs = new BS(String.valueOf(i)); - LexicographicList bis = new LexicographicList(bi); - LexicographicList bss = new LexicographicList(bs); - assertTrue(m.putIfAbsent(bis, true) == null); + LexicographicList bis = new LexicographicList<>(bi); + LexicographicList bss = new LexicographicList<>(bs); + assertNull(m.putIfAbsent(bis, true)); assertTrue(m.containsKey(bis)); if (m.putIfAbsent(bss, true) == null) assertTrue(m.containsKey(bss)); @@ -160,14 +161,13 @@ public class ConcurrentHashMapTest exten */ public void testGenericComparable2() { int size = 500; // makes measured test run time -> 60ms - ConcurrentHashMap m = - new ConcurrentHashMap(); + ConcurrentHashMap m = new ConcurrentHashMap<>(); for (int i = 0; i < size; i++) { m.put(Collections.singletonList(new BI(i)), true); } for (int i = 0; i < size; i++) { - LexicographicList bis = new LexicographicList(new BI(i)); + LexicographicList bis = new LexicographicList<>(new BI(i)); assertTrue(m.containsKey(bis)); } } @@ -178,8 +178,7 @@ public class ConcurrentHashMapTest exten */ public void testMixedComparable() { int size = 1200; // makes measured test run time -> 35ms - ConcurrentHashMap map = - new ConcurrentHashMap(); + ConcurrentHashMap map = new ConcurrentHashMap<>(); Random rng = new Random(); for (int i = 0; i < size; i++) { Object x; @@ -786,7 +785,7 @@ public class ConcurrentHashMapTest exten } /** - * A deserialized map equals original + * A deserialized/reserialized map equals original */ public void testSerialization() throws Exception { Map x = map5(); @@ -837,30 +836,20 @@ public class ConcurrentHashMapTest exten assertEquals(mapSize, map.size()); } - /** - * Tests performance of computeIfAbsent when the element is present. - * See JDK-8161372 - * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testcomputeIfAbsent_performance -Djsr166.expensiveTests=true tck - */ - public void testcomputeIfAbsent_performance() { - final int mapSize = 20; - final int iterations = expensiveTests ? (1 << 23) : mapSize * 2; - final int threads = expensiveTests ? 10 : 2; - final ConcurrentHashMap map = new ConcurrentHashMap<>(); - for (int i = 0; i < mapSize; i++) - map.put(i, i); - final ExecutorService pool = Executors.newFixedThreadPool(2); - try (PoolCleaner cleaner = cleaner(pool)) { - Runnable r = new CheckedRunnable() { - public void realRun() { - int result = 0; - for (int i = 0; i < iterations; i++) - result += map.computeIfAbsent(i % mapSize, (k) -> k + k); - if (result == -42) throw new Error(); - }}; - for (int i = 0; i < threads; i++) - pool.execute(r); - } + public void testReentrantComputeIfAbsent() { + ConcurrentHashMap map = new ConcurrentHashMap<>(16); + try { + for (int i = 0; i < 100; i++) { // force a resize + map.computeIfAbsent(i, key -> findValue(map, key)); + } + fail("recursive computeIfAbsent should throw IllegalStateException"); + } catch (IllegalStateException success) {} + } + + private Integer findValue(ConcurrentHashMap map, + Integer key) { + return (key % 5 == 0) ? key : + map.computeIfAbsent(key + 1, k -> findValue(map, k)); } }