mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
Merge
This commit is contained in:
commit
cf25383d19
2 changed files with 62 additions and 59 deletions
|
@ -1915,44 +1915,48 @@ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
|
||||||
* throws TimeoutException on timeout.
|
* throws TimeoutException on timeout.
|
||||||
*/
|
*/
|
||||||
private Object timedGet(long nanos) throws TimeoutException {
|
private Object timedGet(long nanos) throws TimeoutException {
|
||||||
if (Thread.interrupted())
|
|
||||||
return null;
|
|
||||||
if (nanos > 0L) {
|
|
||||||
long d = System.nanoTime() + nanos;
|
long d = System.nanoTime() + nanos;
|
||||||
long deadline = (d == 0L) ? 1L : d; // avoid 0
|
long deadline = (d == 0L) ? 1L : d; // avoid 0
|
||||||
|
boolean interrupted = false, queued = false;
|
||||||
Signaller q = null;
|
Signaller q = null;
|
||||||
boolean queued = false;
|
Object r = null;
|
||||||
Object r;
|
for (;;) { // order of checking interrupt, result, timeout matters
|
||||||
while ((r = result) == null) { // similar to untimed
|
if (interrupted || (interrupted = Thread.interrupted()))
|
||||||
if (q == null) {
|
break;
|
||||||
|
else if ((r = result) != null)
|
||||||
|
break;
|
||||||
|
else if (nanos <= 0L)
|
||||||
|
break;
|
||||||
|
else if (q == null) {
|
||||||
q = new Signaller(true, nanos, deadline);
|
q = new Signaller(true, nanos, deadline);
|
||||||
if (Thread.currentThread() instanceof ForkJoinWorkerThread)
|
if (Thread.currentThread() instanceof ForkJoinWorkerThread)
|
||||||
ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
|
ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
|
||||||
}
|
}
|
||||||
else if (!queued)
|
else if (!queued)
|
||||||
queued = tryPushStack(q);
|
queued = tryPushStack(q);
|
||||||
else if (q.nanos <= 0L)
|
|
||||||
break;
|
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
ForkJoinPool.managedBlock(q);
|
ForkJoinPool.managedBlock(q);
|
||||||
|
interrupted = q.interrupted;
|
||||||
|
nanos = q.nanos;
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
q.interrupted = true;
|
interrupted = true;
|
||||||
}
|
|
||||||
if (q.interrupted)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (q != null && queued) {
|
}
|
||||||
|
if (q != null) {
|
||||||
q.thread = null;
|
q.thread = null;
|
||||||
if (r == null)
|
if (r == null)
|
||||||
cleanStack();
|
cleanStack();
|
||||||
}
|
}
|
||||||
if (r != null || (r = result) != null)
|
if (r != null) {
|
||||||
|
if (interrupted)
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
postComplete();
|
postComplete();
|
||||||
if (r != null || (q != null && q.interrupted))
|
|
||||||
return r;
|
return r;
|
||||||
}
|
} else if (interrupted)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import static java.util.concurrent.TimeUnit.DAYS;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -33,57 +34,55 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||||
* @key randomness
|
* @key randomness
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// TODO: incorporate into CompletableFuture tck tests
|
||||||
|
|
||||||
public class SwallowedInterruptedException {
|
public class SwallowedInterruptedException {
|
||||||
static final int ITERATIONS = 100;
|
static final int ITERATIONS = 100;
|
||||||
|
|
||||||
public static void main(String[] args) throws Throwable {
|
public static void main(String[] args) throws Throwable {
|
||||||
|
ThreadLocalRandom rnd = ThreadLocalRandom.current();
|
||||||
for (int i = 1; i <= ITERATIONS; i++) {
|
for (int i = 1; i <= ITERATIONS; i++) {
|
||||||
System.out.format("Iteration %d%n", i);
|
boolean timed = rnd.nextBoolean();
|
||||||
|
long sleepMillis = rnd.nextLong(10);
|
||||||
|
|
||||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||||
CountDownLatch running = new CountDownLatch(1);
|
CountDownLatch threadRunning = new CountDownLatch(1);
|
||||||
AtomicReference<String> failed = new AtomicReference<>();
|
AtomicReference<Throwable> fail = new AtomicReference<>();
|
||||||
|
|
||||||
Thread thread = new Thread(() -> {
|
Thread thread = new Thread(() -> {
|
||||||
// signal main thread that child is running
|
threadRunning.countDown();
|
||||||
running.countDown();
|
|
||||||
|
|
||||||
// invoke Future.get, it complete with the interrupt status set or
|
|
||||||
// else throw InterruptedException with the interrupt status not set.
|
|
||||||
try {
|
try {
|
||||||
future.get();
|
Void result = (timed) ? future.get(1, DAYS) : future.get();
|
||||||
|
|
||||||
// interrupt status should be set
|
|
||||||
if (!Thread.currentThread().isInterrupted()) {
|
if (!Thread.currentThread().isInterrupted()) {
|
||||||
failed.set("Future.get completed with interrupt status not set");
|
fail.set(new AssertionError(
|
||||||
|
"Future.get completed with interrupt status not set"));
|
||||||
}
|
}
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
// interrupt status should be cleared
|
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
failed.set("InterruptedException with interrupt status set");
|
fail.set(new AssertionError(
|
||||||
|
"InterruptedException with interrupt status set"));
|
||||||
}
|
}
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
failed.set("Unexpected exception " + ex);
|
fail.set(ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thread.setDaemon(true);
|
|
||||||
thread.start();
|
thread.start();
|
||||||
|
threadRunning.await();
|
||||||
|
|
||||||
// wait for thread to run
|
// interrupt thread, then set result after an optional (random) delay
|
||||||
running.await();
|
|
||||||
|
|
||||||
// interrupt thread and set result after an optional (random) delay
|
|
||||||
thread.interrupt();
|
thread.interrupt();
|
||||||
long sleepMillis = ThreadLocalRandom.current().nextLong(10);
|
|
||||||
if (sleepMillis > 0)
|
if (sleepMillis > 0)
|
||||||
Thread.sleep(sleepMillis);
|
Thread.sleep(sleepMillis);
|
||||||
future.complete(null);
|
future.complete(null);
|
||||||
|
|
||||||
// wait for thread to terminate and check for failure
|
|
||||||
thread.join();
|
thread.join();
|
||||||
String failedReason = failed.get();
|
if (fail.get() != null) {
|
||||||
if (failedReason != null) {
|
throw new AssertionError(
|
||||||
throw new RuntimeException("Test failed: " + failedReason);
|
String.format("Test failed at iteration %d with [timed=%s sleepMillis=%d]",
|
||||||
|
i, timed, sleepMillis),
|
||||||
|
fail.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue