Я предоставляю метод в библиотеке, которая возвращает CompletableFuture. Вычисление этого метода происходит на однопоточном Executor, который является моим узким местом, поэтому я не хочу, чтобы какая-либо последующая работа выполнялась в том же потоке.
Если я воспользуюсь простым подходом возврата результата «supplyAsync», я буду показывать свой драгоценный поток вызывающим, которые могут добавлять синхронные операции (например, через thenAccept), которые могут занять некоторое время процессора в этом потоке.
Repro ниже:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CfPlayground {
private ExecutorService preciousExecService = Executors.newFixedThreadPool(1);
CfPlayground() {}
private static void log(String msg) {
System.out.println("[" + Thread.currentThread().getName() + "] " + msg);
}
CompletableFuture<String> asyncOp(String param) {
return CompletableFuture.supplyAsync(() -> {
log("In asyncOp");
return "Hello " + param;
}, preciousExecService);
}
void syncOp(String salutation) {
log("In syncOp: " + salutation);
}
void run() {
log("run");
asyncOp("world").thenAccept(this::syncOp);
}
public static void main(String[] args) throws InterruptedException {
CfPlayground compFuture = new CfPlayground();
compFuture.run();
Thread.sleep(500);
compFuture.preciousExecService.shutdown();
}
}
Это действительно печатает:
[main] run
[pool-1-thread-1] In asyncOp
[pool-1-thread-1] In syncOp: Hello world
Одно решение, которое я нашел, состояло в том, чтобы представить другого Executor и добавить no-op thenApplyAsync с этим исполнителем перед возвратом CompletableFuture
CompletableFuture<String> asyncOp(String param) {
return CompletableFuture.supplyAsync(() -> {
log("In asyncOp");
return "Hello " + param;
}, preciousExecService).thenApplyAsync(s -> s, secondExecService);
}
Это работает, но не выглядит супер элегантно - есть ли лучший способ сделать это?