--- a/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java Sat Sep 14 11:26:26 2019 -0700
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java Sat Sep 14 11:26:26 2019 -0700
@@ -24,37 +24,40 @@
/*
* @test
* @bug 4486658 8010293
- * @summary thread safety of toArray methods of subCollections
+ * @summary thread safety of toArray methods of collection views
* @author Martin Buchholz
*/
+import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ToArray {
public static void main(String[] args) throws Throwable {
- // Execute a number of times to increase the probability of
- // failure if there is an issue
- for (int i = 0; i < 16; i++) {
+ final int runsPerTest = Integer.getInteger("jsr166.runsPerTest", 1);
+ final int reps = 10 * runsPerTest;
+ for (int i = reps; i--> 0; )
executeTest();
- }
}
static void executeTest() throws Throwable {
- final Throwable[] throwable = new Throwable[1];
final ConcurrentHashMap<Integer, Integer> m = new ConcurrentHashMap<>();
-
- // Number of workers equal to the number of processors
- // Each worker will put globally unique keys into the map
- final int nWorkers = Runtime.getRuntime().availableProcessors();
+ final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ final int nCPU = Runtime.getRuntime().availableProcessors();
+ final int minWorkers = 2;
+ final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU));
+ final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1);
final int sizePerWorker = 1024;
final int maxSize = nWorkers * sizePerWorker;
- // The foreman keeps checking that the size of the arrays
- // obtained from the key and value sets is never less than the
- // previously observed size and is never greater than the maximum size
+ // The foreman busy-checks that the size of the arrays obtained
+ // from the keys and values views grows monotonically until it
+ // reaches the maximum size.
+
// NOTE: these size constraints are not specific to toArray and are
// applicable to any form of traversal of the collection views
CompletableFuture<?> foreman = CompletableFuture.runAsync(new Runnable() {
@@ -62,44 +65,37 @@
private boolean checkProgress(Object[] a) {
int size = a.length;
- if (size < prevSize) throw new RuntimeException("WRONG WAY");
- if (size > maxSize) throw new RuntimeException("OVERSHOOT");
- if (size == maxSize) return true;
+ if (size < prevSize || size > maxSize)
+ throw new AssertionError(
+ String.format("prevSize=%d size=%d maxSize=%d",
+ prevSize, size, maxSize));
prevSize = size;
- return false;
+ return size == maxSize;
}
- @Override
public void run() {
- try {
- Integer[] empty = new Integer[0];
- while (true) {
- if (checkProgress(m.values().toArray())) return;
- if (checkProgress(m.keySet().toArray())) return;
- if (checkProgress(m.values().toArray(empty))) return;
- if (checkProgress(m.keySet().toArray(empty))) return;
- }
- }
- catch (Throwable t) {
- throwable[0] = t;
- }
+ Integer[] empty = new Integer[0];
+ for (;;)
+ if (checkProgress(m.values().toArray())
+ & checkProgress(m.keySet().toArray())
+ & checkProgress(m.values().toArray(empty))
+ & checkProgress(m.keySet().toArray(empty)))
+ return;
}
});
- // Create workers
- // Each worker will put globally unique keys into the map
- CompletableFuture<?>[] workers = IntStream.range(0, nWorkers).
- mapToObj(w -> CompletableFuture.runAsync(() -> {
- for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
- m.put(o + i, i);
- })).
- toArray(CompletableFuture<?>[]::new);
+ // Each worker puts globally unique keys into the map
+ List<CompletableFuture<?>> workers =
+ IntStream.range(0, nWorkers)
+ .mapToObj(w -> (Runnable) () -> {
+ for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
+ m.put(o + i, i);
+ })
+ .map(CompletableFuture::runAsync)
+ .collect(Collectors.toList());
- // Wait for workers and then foreman to complete
- CompletableFuture.allOf(workers).join();
+ // Wait for workers and foreman to complete
+ workers.forEach(CompletableFuture<?>::join);
foreman.join();
-
- if (throwable[0] != null)
- throw throwable[0];
}
}