Details
-
Bug
-
Resolution: Fixed
-
P2
-
8
-
b120
-
x86
-
linux
-
Verified
Backports
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8030329 | 8u5 | Paul Sandoz | P2 | Resolved | Fixed | b01 |
Description
Parallel execution of Stream.forEachOrdered can fail to terminate.
This is due to the CHM used by ForEachOps.ForEachOrderedTask.
Concurrent calls to CHM.put can result in lost entries if a put by one thread is resizing the table (a transfer) while puts by other threads are adding new nodes (holding an entries) to the link list of nodes whose entries all hash to the same value.
The issue can be reliably reproduced with the following program:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class TestCHM {
static final int N = Integer.getInteger("n", 128);
static final int I = Integer.getInteger("i", 10);
public static void main(String[] args) throws Exception {
for (int i = 0; i < I; i++) {
System.out.print(".");
test();
}
System.out.println();
}
static class X {
int hc = ThreadLocalRandom.current().nextInt(1, 9);
public int hashCode() { return hc; }
}
public static void test() throws Exception {
ConcurrentHashMap<Object, Object> m = new ConcurrentHashMap<>();
CountDownLatch s = new CountDownLatch(1);
Supplier<Runnable> putter = () -> () -> {
try {
s.await();
}
catch (InterruptedException e) {
}
for (int i = 0; i < N; i++) {
Object o = new X();
m.put(o, o);
if (!m.containsKey(o)) {
System.out.println("PUT: Entry does not exist!");
}
}
};
int ps = Runtime.getRuntime().availableProcessors();
Stream<CompletableFuture> putters = IntStream.range(0, ps)
.mapToObj(i -> putter.get())
.map(CompletableFuture::runAsync);
CompletableFuture all = CompletableFuture.allOf(
putters.toArray(CompletableFuture[]::new));
s.countDown();
all.join();
}
}
This is due to the CHM used by ForEachOps.ForEachOrderedTask.
Concurrent calls to CHM.put can result in lost entries if a put by one thread is resizing the table (a transfer) while puts by other threads are adding new nodes (holding an entries) to the link list of nodes whose entries all hash to the same value.
The issue can be reliably reproduced with the following program:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class TestCHM {
static final int N = Integer.getInteger("n", 128);
static final int I = Integer.getInteger("i", 10);
public static void main(String[] args) throws Exception {
for (int i = 0; i < I; i++) {
System.out.print(".");
test();
}
System.out.println();
}
static class X {
int hc = ThreadLocalRandom.current().nextInt(1, 9);
public int hashCode() { return hc; }
}
public static void test() throws Exception {
ConcurrentHashMap<Object, Object> m = new ConcurrentHashMap<>();
CountDownLatch s = new CountDownLatch(1);
Supplier<Runnable> putter = () -> () -> {
try {
s.await();
}
catch (InterruptedException e) {
}
for (int i = 0; i < N; i++) {
Object o = new X();
m.put(o, o);
if (!m.containsKey(o)) {
System.out.println("PUT: Entry does not exist!");
}
}
};
int ps = Runtime.getRuntime().availableProcessors();
Stream<CompletableFuture> putters = IntStream.range(0, ps)
.mapToObj(i -> putter.get())
.map(CompletableFuture::runAsync);
CompletableFuture all = CompletableFuture.allOf(
putters.toArray(CompletableFuture[]::new));
s.countDown();
all.join();
}
}
Attachments
Issue Links
- backported by
-
JDK-8030329 Concurrent calls to CHM.put can fail to add the key/value to the map
- Resolved
- duplicates
-
JDK-8029454 java/util/stream tests fail by timeout
- Resolved
-
JDK-8030786 [TESTBUG] java/util/stream/test/org/openjdk/tests/java/util/stream/DistinctOpTest.java timeouts
- Resolved
-
JDK-8031480 Test java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java fails by Timeout on Solaris sparc 64-bit
- Resolved