8221168: java/util/concurrent/CountDownLatch/Basic.java fails

Reviewed-by: martin, alanb
This commit is contained in:
Doug Lea 2019-09-14 11:24:14 -07:00
parent f634f777f6
commit 064f69d6ab

@ -23,70 +23,57 @@
/* /*
* @test * @test
* @bug 6332435 * @bug 6332435 8221168
* @summary Basic tests for CountDownLatch * @summary Basic tests for CountDownLatch
* @library /test/lib * @library /test/lib
* @author Seetharam Avadhanam, Martin Buchholz * @author Seetharam Avadhanam, Martin Buchholz
*/ */
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import jdk.test.lib.Utils; import jdk.test.lib.Utils;
public class Basic { public class Basic {
static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000); static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
interface AwaiterFactory {
Awaiter getAwaiter();
}
abstract static class Awaiter extends Thread { abstract static class Awaiter extends Thread {
private volatile Throwable result = null; volatile Throwable exception;
protected void result(Throwable result) { this.result = result; } volatile boolean interrupted;
public Throwable result() { return this.result; } abstract void realRun() throws Exception;
public final void run() {
try { realRun(); }
catch (Throwable ex) { exception = ex; }
interrupted = Thread.interrupted();
};
} }
private void toTheStartingGate(CountDownLatch gate) { static Awaiter awaiter(CountDownLatch latch,
try { CountDownLatch gate) {
gate.await(); return new Awaiter() {
} public void realRun() throws InterruptedException {
catch (Throwable t) { fail(t); } gate.countDown();
}
private Awaiter awaiter(final CountDownLatch latch,
final CountDownLatch gate) {
return new Awaiter() { public void run() {
System.out.println("without millis: " + latch.toString());
gate.countDown();
try {
latch.await(); latch.await();
System.out.println("without millis - ComingOut"); }};
}
catch (Throwable result) { result(result); }}};
} }
private Awaiter awaiter(final CountDownLatch latch, static Awaiter awaiter(CountDownLatch latch,
final CountDownLatch gate, CountDownLatch gate,
final long millis) { long timeoutMillis) {
return new Awaiter() { public void run() { return new Awaiter() {
System.out.println("with millis: "+latch.toString()); public void realRun() throws InterruptedException {
gate.countDown(); gate.countDown();
latch.await(timeoutMillis, TimeUnit.MILLISECONDS);
try { }};
latch.await(millis, TimeUnit.MILLISECONDS);
System.out.println("with millis - ComingOut");
}
catch (Throwable result) { result(result); }}};
} }
AwaiterFactory awaiterFactory(CountDownLatch latch, CountDownLatch gate) { static Supplier<Awaiter> randomAwaiterSupplier(
return () -> awaiter(latch, gate); CountDownLatch latch, CountDownLatch gate) {
} return () -> (ThreadLocalRandom.current().nextBoolean())
? awaiter(latch, gate)
AwaiterFactory timedAwaiterFactory(CountDownLatch latch, CountDownLatch gate) { : awaiter(latch, gate, LONG_DELAY_MS);
return () -> awaiter(latch, gate, LONG_DELAY_MS);
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
@ -94,28 +81,24 @@ public class Basic {
//---------------------------------------------------------------- //----------------------------------------------------------------
public static void normalUse() throws Throwable { public static void normalUse() throws Throwable {
int count = 0; int count = 0;
Basic test = new Basic();
CountDownLatch latch = new CountDownLatch(3); CountDownLatch latch = new CountDownLatch(3);
Awaiter[] a = new Awaiter[12]; Awaiter[] a = new Awaiter[12];
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
CountDownLatch gate = new CountDownLatch(4); CountDownLatch gate = new CountDownLatch(4);
AwaiterFactory factory1 = test.awaiterFactory(latch, gate); Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate); a[count] = s.get(); a[count++].start();
a[count] = factory1.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory1.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory2.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory2.getAwaiter(); a[count++].start(); gate.await();
test.toTheStartingGate(gate);
System.out.println("Main Thread: " + latch.toString());
latch.countDown(); latch.countDown();
checkCount(latch, 2-i); checkCount(latch, 2-i);
} }
for (int i = 0; i < 12; i++) for (Awaiter awaiter : a)
a[i].join(); awaiter.join();
for (Awaiter awaiter : a)
for (int i = 0; i < 12; i++) checkException(awaiter, null);
checkResult(a[i], null);
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
@ -123,38 +106,38 @@ public class Basic {
//---------------------------------------------------------------- //----------------------------------------------------------------
public static void threadInterrupted() throws Throwable { public static void threadInterrupted() throws Throwable {
int count = 0; int count = 0;
Basic test = new Basic();
CountDownLatch latch = new CountDownLatch(3); CountDownLatch latch = new CountDownLatch(3);
Awaiter[] a = new Awaiter[12]; Awaiter[] a = new Awaiter[12];
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
CountDownLatch gate = new CountDownLatch(4); CountDownLatch gate = new CountDownLatch(4);
AwaiterFactory factory1 = test.awaiterFactory(latch, gate); Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate); a[count] = s.get(); a[count++].start();
a[count] = factory1.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory1.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory2.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory2.getAwaiter(); a[count++].start(); gate.await();
a[count-1].interrupt(); a[count-1].interrupt();
test.toTheStartingGate(gate);
System.out.println("Main Thread: " + latch.toString());
latch.countDown(); latch.countDown();
checkCount(latch, 2-i); checkCount(latch, 2-i);
} }
for (int i = 0; i < 12; i++) for (Awaiter awaiter : a)
a[i].join(); awaiter.join();
for (int i = 0; i < a.length; i++) {
for (int i = 0; i < 12; i++) Awaiter awaiter = a[i];
checkResult(a[i], Throwable ex = awaiter.exception;
(i % 4) == 3 ? InterruptedException.class : null); if ((i % 4) == 3 && !awaiter.interrupted)
checkException(awaiter, InterruptedException.class);
else
checkException(awaiter, null);
}
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
// One thread timed out // One thread timed out
//---------------------------------------------------------------- //----------------------------------------------------------------
public static void timeOut() throws Throwable { public static void timeOut() throws Throwable {
int count =0; int count = 0;
Basic test = new Basic();
CountDownLatch latch = new CountDownLatch(3); CountDownLatch latch = new CountDownLatch(3);
Awaiter[] a = new Awaiter[12]; Awaiter[] a = new Awaiter[12];
@ -162,54 +145,56 @@ public class Basic {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
CountDownLatch gate = new CountDownLatch(4); CountDownLatch gate = new CountDownLatch(4);
AwaiterFactory factory1 = test.awaiterFactory(latch, gate); Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate); a[count] = awaiter(latch, gate, timeout[i]); a[count++].start();
a[count] = test.awaiter(latch, gate, timeout[i]); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory1.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory2.getAwaiter(); a[count++].start(); a[count] = s.get(); a[count++].start();
a[count] = factory2.getAwaiter(); a[count++].start(); gate.await();
test.toTheStartingGate(gate);
System.out.println("Main Thread: " + latch.toString());
latch.countDown(); latch.countDown();
checkCount(latch, 2-i); checkCount(latch, 2-i);
} }
for (int i = 0; i < 12; i++) for (Awaiter awaiter : a)
a[i].join(); awaiter.join();
for (Awaiter awaiter : a)
for (int i = 0; i < 12; i++) checkException(awaiter, null);
checkResult(a[i], null);
} }
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
normalUse(); try {
threadInterrupted(); normalUse();
timeOut(); } catch (Throwable ex) { fail(ex); }
try {
threadInterrupted();
} catch (Throwable ex) { fail(ex); }
try {
timeOut();
} catch (Throwable ex) { fail(ex); }
if (failures.get() > 0L) if (failures.get() > 0L)
throw new AssertionError(failures.get() + " failures"); throw new AssertionError(failures.get() + " failures");
} }
private static final AtomicInteger failures = new AtomicInteger(0); static final AtomicInteger failures = new AtomicInteger(0);
private static void fail(String msg) { static void fail(String msg) {
fail(new AssertionError(msg)); fail(new AssertionError(msg));
} }
private static void fail(Throwable t) { static void fail(Throwable t) {
t.printStackTrace(); t.printStackTrace();
failures.getAndIncrement(); failures.getAndIncrement();
} }
private static void checkCount(CountDownLatch b, int expected) { static void checkCount(CountDownLatch b, int expected) {
if (b.getCount() != expected) if (b.getCount() != expected)
fail("Count = " + b.getCount() + fail("Count = " + b.getCount() +
", expected = " + expected); ", expected = " + expected);
} }
private static void checkResult(Awaiter a, Class c) { static void checkException(Awaiter awaiter, Class<? extends Throwable> c) {
Throwable t = a.result(); Throwable ex = awaiter.exception;
if (! ((t == null && c == null) || c.isInstance(t))) { if (! ((ex == null && c == null) || c.isInstance(ex)))
System.out.println("Mismatch: " + t + ", " + c.getName()); fail("Expected: " + c + ", got: " + ex);
failures.getAndIncrement();
}
} }
} }