从调用线程运行CompletableFuture.thenAccept?

时间:2016-04-29 01:16:55

标签: java multithreading concurrency

我想调用CompletableFuture.supplyAsync()将阻塞任务委托给另一个线程。一旦该任务完成,我希望CompletableFuture.thenAccept使用者在调用线程的上下文中运行。

例如:

// Thread 1

CompletableFuture.supplyAsync(() -> {
   // Thread 2

   return BlockingMethod();
}).thenAccept((
   Object r) -> {

   // Thread 1
});

以下代码表明CompletableFuture.thenAccept在自己的线程中运行;可能与CompletableFuture.supplyAsync相同的池,因为我在运行它时得到相同的线程ID:

System.out.println("Sync thread supply " + Thread.currentThread().getId());

CompletableFuture.supplyAsync(() -> {

   System.out.println("Async thread " + Thread.currentThread().getId());

   try {
      Thread.sleep(2000);
   }
   catch (Exception e) {
      e.printStackTrace();
   }

   return true;
}).thenAccept((
   Boolean r) -> {

   System.out.println("Sync thread consume " + Thread.currentThread().getId());
});

Thread.sleep(3000);

是否可以让CompletableFuture.thenAccept与调用线程同时运行?

2 个答案:

答案 0 :(得分:3)

CompletableFuture只会在收件人Consumer(由thenAccept返回的)完成后执行CompletableFuture注册的supplyAsync,因为它需要它完成的价值。

如果在调用CompletableFuture时接收器thenAccept完成,则Consumer将在调用线程中执行。否则,它将在完成Supplier提交给supplyAsync的任何线程上执行。

  

是否可以同时运行CompletableFuture.thenAccept   与调用线程?

这是一个令人困惑的问题,因为一个线程一次只能运行一件事。单个线程没有并发 Concurrently 是跨多个线程的属性。

如果您希望Consumer在调用thenAccept的同一线程上运行,然后在join上运行CompletableFuture,则阻止此线程直到将来完成。然后,您可以自己执行Consumer或致电thenAccept为您执行。

例如

CompletableFuture<Boolean> receiver = CompletableFuture.supplyAsync(() -> {
    System.out.println("Async thread " + Thread.currentThread().getId());

    try {
        Thread.sleep(2000);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return true;
});

receiver.join();
Consumer<Boolean> consumer = (Boolean r) -> {
    System.out.println("Sync thread consume " + Thread.currentThread().getId());
};

consumer.accept(receiver.get());

(省略了异常处理。)

如果您希望Consumer与提供给Supplier的{​​{1}}并行运行,那是不可能的。 supplyAsync意味着消耗Consumer生成的值。 <{1}}完成后,该值才可用。

答案 1 :(得分:0)

如果我理解你的想法,你想要分配I / O密集型任务,但在“事件循环”(想想Javascript)中进行所有处理,那么你的代码可以转换为

Executor eventLoop = Executors.newSingleThreadExecutor();
Executor ioMultiplexor = Executors.newCachedThreadPool();

eventLoop.execute(() -> {
    System.out.println("event loop thread supply " + Thread.currentThread().getId());
    CompletableFuture.supplyAsync(() -> {
        System.out.println("I/O multiplexor thread " + Thread.currentThread().getId());
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }, ioMultiplexor).thenAcceptAsync((Boolean r) -> {
        System.out.println("event loop thread consume " + Thread.currentThread().getId());
    }, eventLoop);
});

Thread.sleep(3000);
// shut down executors

打印

event loop thread supply 10
I/O multiplexor thread 11
event loop thread consume 10

如果此代码用于某些请求处理,其中可能存在许多并发请求,那么您可能希望拥有一个全局eventLoop和一个全局ioMultiplexer,并且您还希望释放完成将任务提交到eventLoop后,主请求处理线程。