简体   繁体   English

从调用线程运行 CompletableFuture.thenAccept?

[英]Running CompletableFuture.thenAccept from the calling thread?

I want to call CompletableFuture.supplyAsync() to delegate a blocking task to another thread.我想调用CompletableFuture.supplyAsync()将阻塞任务委托给另一个线程。 Once that task completes I would like for the CompletableFuture.thenAccept consumer to run in the context of the calling thread.一旦该任务完成,我希望CompletableFuture.thenAccept使用者在调用线程的上下文中运行。

For example:例如:

// Thread 1

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

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

   // Thread 1
});

The following code suggests that CompletableFuture.thenAccept runs in its own thread;下面的代码表明CompletableFuture.thenAccept在它自己的线程中运行; probably the same pool as CompletableFuture.supplyAsync as I get the same thread ID when I run it:可能与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);

Is it possible to have CompletableFuture.thenAccept run concurrently with the calling thread?是否可以让CompletableFuture.thenAccept与调用线程同时运行?

The CompletableFuture will only execute the Consumer you register with thenAccept when the receiver CompletableFuture (one returned by supplyAsync ) is completed, since it needs the value it was completed with. CompletableFuture只会在接收器CompletableFuture (由supplyAsync返回的supplyAsync )完成时执行您向thenAccept注册的Consumer ,因为它需要完成它的值。

If the receiver CompletableFuture is complete when thenAccept is invoked, then the Consumer will be executed in the calling thread.如果调用thenAccept时接收器CompletableFuture完成,则Consumer将在调用线程中执行。 Otherwise, it will execute on whatever thread completes the Supplier submitted to supplyAsync .否则,它将在完成提交给supplyAsyncSupplier任何线程上执行。

Is it possible to have CompletableFuture.thenAccept run concurrently with the calling thread?是否可以让CompletableFuture.thenAccept与调用线程同时运行?

This is a confusing question because a thread can only run one thing at a time.这是一个令人困惑的问题,因为一个线程一次只能运行一件事。 There's no concurrently for a single thread.单个线程没有并发 Concurrently is a property that spans multiple threads. Concurrently是一个跨越多个线程的属性。

If you want the Consumer to run on the same thread that invoked thenAccept , then join on the CompletableFuture , blocking this thread until the future is completed.如果您希望Consumer在调用thenAccept的同一线程上运行,则join CompletableFuture ,阻塞该线程直到未来完成。 You can then execute the Consumer yourself or call thenAccept to execute it for you.然后您可以自己执行Consumer或调用thenAccept为您执行它。

For example例如

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());

(Exception handling omitted.) (省略异常处理。)


If you want the Consumer to run in parallel with the Supplier supplied to supplyAsync , that's not possible.如果您希望Consumer与提供给supplyAsyncSupplier并行运行,那是不可能的。 That Consumer is meant to consume the value produced by the Supplier .Consumer旨在消耗Supplier产生的价值。 That value isn't available until the Supplier is finished.Supplier完成之前,该值不可用。

If I understand your idea right that you want to fork I/O-intensive tasks but do all processing in the "event loop" (think Javascript), then your code could be translated to如果我理解你的想法是正确的,你想要分叉 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

This prints这打印

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

If this code is used for some request handling where there can be many concurrent requests, you would probably want to have one global eventLoop and one global ioMultiplexer , and you would also want to release the main request handling thread once it finishes submitting the task onto eventLoop .如果此代码用于某些可能有许多并发请求的请求处理,您可能希望拥有一个全局eventLoop和一个全局ioMultiplexer ,并且您还希望在完成提交任务后释放主请求处理线程eventLoop

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM