Skip to content

Commit f720c8a

Browse files
committed
More stuff
1 parent c6658d2 commit f720c8a

File tree

3 files changed

+74
-29
lines changed

3 files changed

+74
-29
lines changed

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -353,4 +353,3 @@ Otherwise you may be bottlenecking on a static single-threaded `ScheduledExecuto
353353
# TODO:
354354
workarounds for timeout-issue
355355
Explain minimalCompletionStage and delayedExecutor
356-
Rename OnTimeoutTest -> CompleteOnTimeoutTest

pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
<version>4.12</version>
2121
<scope>test</scope>
2222
</dependency>
23+
<dependency>
24+
<groupId>com.google.guava</groupId>
25+
<artifactId>guava</artifactId>
26+
<version>28.1-jre</version>
27+
<scope>test</scope>
28+
</dependency>
2329
</dependencies>
2430
<build>
2531
<plugins>

src/test/java/se/krka/futures/OnTimeoutTest.java

+68-28
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,60 @@
11
package se.krka.futures;
22

3+
import com.google.common.util.concurrent.MoreExecutors;
34
import org.junit.Test;
45

56
import java.io.Closeable;
6-
import java.io.IOException;
77
import java.util.concurrent.CompletableFuture;
88
import java.util.concurrent.ExecutionException;
9+
import java.util.concurrent.Executor;
910
import java.util.concurrent.TimeUnit;
1011
import java.util.concurrent.TimeoutException;
12+
import java.util.concurrent.atomic.AtomicBoolean;
1113

1214
import static org.junit.Assert.assertEquals;
1315
import static org.junit.Assert.assertTrue;
14-
import static org.junit.Assert.fail;
1516

1617
public class OnTimeoutTest {
1718
@Test
1819
public void testTimeoutNotBlocking() throws Exception {
20+
waitForNotBlocking();
1921
assertTrue(measureTimeout() < 200);
2022
}
2123

2224
@Test
2325
public void testTimeoutNotBlockingTwice() throws Exception {
26+
waitForNotBlocking();
2427
assertTrue(measureTimeout() < 200);
2528
assertTrue(measureTimeout() < 200);
2629
}
2730

2831
@Test
2932
public void testTimeoutBlocking() throws Exception {
33+
waitForNotBlocking();
3034
try (Killer killer = new Killer(killTimeout())) {
3135
expectFailure();
3236
}
3337
}
3438

3539
@Test
3640
public void testTimeoutBlocking2() throws Exception {
41+
waitForNotBlocking();
3742
try (Killer killer = new Killer(killTimeout2())) {
3843
expectFailure();
3944
}
4045
}
4146

47+
@Test
48+
public void testTimeoutBlockingWithDelayedExecutor() throws Exception {
49+
waitForNotBlocking();
50+
try (Killer killer = new Killer(killTimeout3())) {
51+
expectFailure();
52+
}
53+
}
54+
4255
private void expectFailure() throws Exception {
4356
long time = measureTimeout();
44-
assertTrue("time was " + time, time >= 1000);
57+
assertTrue("time was " + time, time >= 900);
4558
}
4659

4760
private long measureTimeout() throws InterruptedException, TimeoutException {
@@ -59,36 +72,63 @@ private long measureTimeout() throws InterruptedException, TimeoutException {
5972
}
6073

6174
private CompletableFuture<String> killTimeout() {
62-
return new CompletableFuture<String>()
63-
.orTimeout(1, TimeUnit.MILLISECONDS)
64-
.handle((s, t) -> {
65-
try {
66-
sleepOnThread();
67-
return "";
68-
} catch (InterruptedException e) {
69-
throw new RuntimeException(e);
70-
}
71-
})
72-
.exceptionally(Throwable::getMessage);
75+
waitForNotBlocking();
76+
CompletableFuture<String> future = new CompletableFuture<String>()
77+
.orTimeout(10, TimeUnit.MILLISECONDS)
78+
.exceptionally(Throwable::getMessage)
79+
.thenApply(s -> sleepOnThread(s, 1000));
80+
waitForBlocking();
81+
return future;
7382
}
7483

7584
private CompletableFuture<String> killTimeout2() {
76-
return new CompletableFuture<String>()
77-
.completeOnTimeout("", 1, TimeUnit.MILLISECONDS)
78-
.thenApply(s -> {
79-
try {
80-
sleepOnThread();
81-
return s;
82-
} catch (InterruptedException e) {
83-
return s;
84-
}
85-
});
85+
CompletableFuture<String> future = new CompletableFuture<String>()
86+
.completeOnTimeout("", 10, TimeUnit.MILLISECONDS)
87+
.thenApply(s -> sleepOnThread(s, 1000));
88+
waitForBlocking();
89+
return future;
8690
}
8791

88-
private void sleepOnThread() throws InterruptedException {
89-
int millis = 1000;
90-
System.out.println("Sleeping on " + Util.currThread() + " for " + millis + " ms");
91-
Thread.sleep(millis);
92+
private CompletableFuture<String> killTimeout3() {
93+
Executor executor = CompletableFuture.delayedExecutor(1, TimeUnit.MILLISECONDS, MoreExecutors.directExecutor());
94+
CompletableFuture<String> future = new CompletableFuture<>();
95+
executor.execute(() -> {
96+
sleepOnThread(null, 1000);
97+
future.complete("value");
98+
});
99+
waitForBlocking();
100+
return future;
101+
}
102+
103+
private static final AtomicBoolean BLOCKING_COMPLETABLE_FUTURE_DELAY_SCHEDULER = new AtomicBoolean(false);
104+
105+
private <T> T sleepOnThread(T value, int millis) {
106+
if (Util.currThread().equals("CompletableFutureDelayScheduler")) {
107+
BLOCKING_COMPLETABLE_FUTURE_DELAY_SCHEDULER.set(true);
108+
}
109+
try {
110+
System.out.println("Sleeping on " + Util.currThread() + " for " + millis + " ms");
111+
Thread.sleep(millis);
112+
} catch (InterruptedException e) {
113+
e.printStackTrace();
114+
} finally {
115+
if (Util.currThread().equals("CompletableFutureDelayScheduler")) {
116+
BLOCKING_COMPLETABLE_FUTURE_DELAY_SCHEDULER.set(false);
117+
}
118+
}
119+
return value;
120+
}
121+
122+
private void waitForBlocking() {
123+
while (!BLOCKING_COMPLETABLE_FUTURE_DELAY_SCHEDULER.get()) {
124+
Thread.yield();
125+
}
126+
}
127+
128+
private void waitForNotBlocking() {
129+
while (BLOCKING_COMPLETABLE_FUTURE_DELAY_SCHEDULER.get()) {
130+
Thread.yield();
131+
}
92132
}
93133

94134
private static class Killer implements Closeable {

0 commit comments

Comments
 (0)