+doc Documented how CompletionStages execute #20513 (#21845)

* Documented how CompletionStages execute #20513

* Fixed the failing test: tests are not necessarily run from "main" thread.

* Addressed pull request comment #20513

* Addressed more PR comments #20513
This commit is contained in:
Oleg Poleshuk 2016-12-12 21:46:37 +01:00 committed by Konrad `ktoso` Malawski
parent 5bcffa2acc
commit c50ecf3287
2 changed files with 217 additions and 0 deletions

View file

@ -50,8 +50,13 @@ import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
import scala.compat.java8.FutureConverters;
import akka.testkit.AkkaJUnitActorSystemResource;
import org.junit.ClassRule;
@ -65,6 +70,8 @@ import akka.actor.ActorRef;
import akka.actor.Props;
import akka.pattern.Patterns;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.*;
public class FutureDocTest extends AbstractJavaTest {
@ -524,6 +531,131 @@ public class FutureDocTest extends AbstractJavaTest {
Await.result(result, Duration.create(2, SECONDS));
}
@Test
public void thenApplyCompletionThread() throws Exception {
//#apply-completion-thread
final ExecutionContext ec = system.dispatcher();
final CountDownLatch countDownLatch = new CountDownLatch(1);
Future<String> scalaFuture = Futures.future(() -> {
assertThat(Thread.currentThread().getName(), containsString("akka.actor.default-dispatcher"));
countDownLatch.await(); // do not complete yet
return "hello";
}, ec);
CompletionStage<String> fromScalaFuture = FutureConverters.toJava(scalaFuture)
.thenApply(s -> { // 1
assertThat(Thread.currentThread().getName(), containsString("ForkJoinPool.commonPool"));
return s;
})
.thenApply(s -> { // 2
assertThat(Thread.currentThread().getName(), containsString("ForkJoinPool.commonPool"));
return s;
})
.thenApply(s -> { // 3
assertThat(Thread.currentThread().getName(), containsString("ForkJoinPool.commonPool"));
return s;
});
countDownLatch.countDown(); // complete scalaFuture
//#apply-completion-thread
fromScalaFuture.toCompletableFuture().get(2, SECONDS);
}
@Test
public void thenApplyMainThread() throws Exception {
final ExecutionContext ec = system.dispatcher();
//#apply-main-thread
Future<String> scalaFuture = Futures.future(() -> {
assertThat(Thread.currentThread().getName(), containsString("akka.actor.default-dispatcher"));
return "hello";
}, ec);
CompletionStage<String> completedStage = FutureConverters.toJava(scalaFuture)
.thenApply(s -> { // 1
assertThat(Thread.currentThread().getName(), containsString("ForkJoinPool.commonPool"));
return s;
});
completedStage.toCompletableFuture().get(2, SECONDS); // complete current CompletionStage
final String currentThread = Thread.currentThread().getName();
CompletionStage<String> stage2 = completedStage
.thenApply(s -> { // 2
assertThat(Thread.currentThread().getName(), is(currentThread));
return s;
})
.thenApply(s -> { // 3
assertThat(Thread.currentThread().getName(), is(currentThread));
return s;
});
//#apply-main-thread
stage2.toCompletableFuture().get(2, SECONDS);
}
@Test
public void thenApplyAsyncDefault() throws Exception {
final ExecutionContext ec = system.dispatcher();
Future<String> scalaFuture = Futures.future(() -> {
assertThat(Thread.currentThread().getName(), containsString("akka.actor.default-dispatcher"));
return "hello";
}, ec);
//#apply-async-default
CompletionStage<String> fromScalaFuture = FutureConverters.toJava(scalaFuture)
.thenApplyAsync(s -> { // 1
assertThat(Thread.currentThread().getName(), containsString("ForkJoinPool.commonPool"));
return s;
})
.thenApplyAsync(s -> { // 2
assertThat(Thread.currentThread().getName(), containsString("ForkJoinPool.commonPool"));
return s;
})
.thenApplyAsync(s -> { // 3
assertThat(Thread.currentThread().getName(), containsString("ForkJoinPool.commonPool"));
return s;
});
//#apply-async-default
fromScalaFuture.toCompletableFuture().get(2, SECONDS);
}
@Test
public void thenApplyAsyncExecutor() throws Exception {
final ExecutionContext ec = system.dispatcher();
Future<String> scalaFuture = Futures.future(() -> {
assertThat(Thread.currentThread().getName(), containsString("akka.actor.default-dispatcher"));
return "hello";
}, ec);
//#apply-async-executor
final Executor ex = system.dispatcher();
CompletionStage<String> fromScalaFuture = FutureConverters.toJava(scalaFuture)
.thenApplyAsync(s -> {
assertThat(Thread.currentThread().getName(), containsString("akka.actor.default-dispatcher"));
return s;
}, ex)
.thenApplyAsync(s -> {
assertThat(Thread.currentThread().getName(), containsString("akka.actor.default-dispatcher"));
return s;
}, ex)
.thenApplyAsync(s -> {
assertThat(Thread.currentThread().getName(), containsString("akka.actor.default-dispatcher"));
return s;
}, ex);
//#apply-async-executor
fromScalaFuture.toCompletableFuture().get(2, SECONDS);
}
public static class MyActor extends UntypedActor {
public void onReceive(Object message) {
if (message instanceof String) {