在与执行线程相同的线程或不同的线程上运行 completablefuture

时间:2021-07-29 11:55:37

标签: java multithreading future completable-future

我有以下类,它在与启动 docker-compose up 的线程相同的线程上运行 FutureTask

有没有办法使用 FutureTask 来实现这一点?

我之所以这么问是因为我最终想利用将多个 CompletableFuture 链接在一起的优势。能够指定它们是在与执行线程相同的线程上运行还是在不同的线程上运行。

CompletableFuture

产生以下输出:

public class SameThreadFutureTask {

  public static void main(String[] args) throws ExecutionException, InterruptedException {

    System.out.println(Thread.currentThread());
    Callable<String> action = new Callable<String>() {
      public String call() {
        try {
          Thread.sleep(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        return "hello "+Thread.currentThread();
      }
    };
    System.out.println("before");

    FutureTask<String> ft = new FutureTask<>(action);
    ft.run();
    System.out.println(ft.get());
    System.out.println("After");
  }
}

2 个答案:

答案 0 :(得分:2)

您可以在没有任何完成的情况下构造一个 new CompletableFuture<>(),并根据需要链接任意数量的操作。然后,当您知道如何完成它时,调用 complete 以在同一线程中完成或调用 completeAsync 以进行异步完成。

final String main = Thread.currentThread().getName();

for(boolean sameThread: new boolean[] { true, false}) {
    System.out.println("will use " + (sameThread? "same thread ("+main+")": "async"));

    CompletableFuture<String> initial = new CompletableFuture<>();
    CompletableFuture<?> result = initial
        .thenApply(s -> {
            System.out.println("toUpperCase in " + Thread.currentThread().getName());
            return s.toUpperCase();
        })
        .thenAccept(s -> System.out.println(
            "final processing of \"" + s + "\" in " + Thread.currentThread().getName()));

    System.out.println("before");
    if(sameThread) {
        initial.complete("hello " + main);
    }
    else {
        initial.completeAsync(() -> "hello " + Thread.currentThread().getName());
    }
    System.out.println("after");

    result.join();
    System.out.println();
}

这演示了两种模式。

will use same thread (main)
before
toUpperCase in main
final processing of "HELLO MAIN" in main
after

will use async
before
after
toUpperCase in ForkJoinPool.commonPool-worker-1
final processing of "HELLO FORKJOINPOOL.COMMONPOOL-WORKER-1" in ForkJoinPool.commonPool-worker-1

请注意,completeAsync 已在 Java 9 中引入。如果您在 Java 8 中需要类似的构造,则必须替换
initial.completeAsync(() -> "hello " + Thread.currentThread().getName());

CompletableFuture.runAsync(() -> {
    try {
        initial.complete("hello " + Thread.currentThread().getName());
    } catch(Throwable t) {
        initial.completeExceptionally(t);
    }
});

答案 1 :(得分:0)

Executor sameThreadExecutor = runnable -> runnable.run();
Runnable myTask = () -> System.out.println("hello "+Thread.currentThread());
CompletableFuture.runAsync(myTask, sameThreadExecutor).get();

<块引用>

能够指定它们是在与执行线程相同的线程上运行还是在不同的线程上运行。

boolean useSameThread = ...;
Executor sameThreadExecutor = runnable -> runnable.run();
Executor forkJoin = ForkJoinPool.commonPool();
Executor preferredExecutor = useSameThread ? sameThreadExecutor : forkJoin;
Runnable hello = () -> System.out.println("hello "+Thread.currentThread());
Runnable helloAgain = () -> System.out.println("hello again " + Thread.currentThread());
Runnable bye = () -> System.out.println("bye " + Thread.currentThread());
CompletableFuture.runAsync(hello, preferredExecutor)
    .thenRunAsync(helloAgain, preferredExecutor)
    .thenRunAsync(bye, preferredExecutor)
    .get();