Java 从 ExecutorService 设置回调

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13116192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 11:33:23  来源:igfitidea点击:

Java set a callback from ExecutorService

javamultithreadingcallbackthreadpoolexecutorservice

提问by Alex

I have a fixedThreadPool that I am using to run a bunch of worker threads to achieve parallel execution of a task with many components.

我有一个 fixedThreadPool,我用它来运行一堆工作线程来实现具有多个组件的任务的并行执行。

When all threads have finished, I retrieve their results (which are quite large) using a method (getResult) and write them to a file.

当所有线程都完成后,我使用方法 (getResult) 检索它们的结果(非常大)并将它们写入文件。

Ultimately, to save memory and be able to see intermediate results, I'd like each thread to write its result to the file as soon as it finishes execution and then free its memory.

最终,为了节省内存并能够看到中间结果,我希望每个线程在完成执行后立即将其结果写入文件,然后释放其内存。

Ordinarily, I'd add code to that effect to the end of the run() method. However, certain other objects in this class also calls these threads, but DO NOT want them to write their results to file - instead they use their results to perform other calculations, which are eventually written to file.

通常,我会在 run() 方法的末尾添加实现该效果的代码。但是,此类中的某些其他对象也调用这些线程,但不希望它们将结果写入文件 - 而是使用它们的结果执行其他计算,这些计算最终会写入文件。

So, I was wondering if it's possible to attach a callback function to the event of a thread finishing using the ExecutorService. That way, I can immediately retrieve its result and free the memory in that scenario, but not break the code when those threads are used in other scenarios.

所以,我想知道是否可以将回调函数附加到使用 ExecutorService 完成的线程的事件。这样,我可以立即检索其结果并在该场景中释放内存,但在其他场景中使用这些线程时不会破坏代码。

Is such a thing possible?

这样的事情可能吗?

回答by Peter

If using Google Guava is an option, you could utilize the ListenableFutureinterface in the following manner:

如果可以选择使用 Google Guava,您可以通过以下方式使用ListenableFuture接口:

  1. Convert an ExecutorServiceto a ListeningExecutorServicevia MoreExecutors.listeningDecorator(existingExecutorService)
  2. The submit(Callable<V>)method of ListeningExecutorServicehas been narrowed to return a ListenableFuture, which is a subinterface of Future.
  3. ListenableFuturehas an addListener()method so you can register a callback to be run when the future is completed.
  1. 转换一个ExecutorServiceListeningExecutorService通过MoreExecutors.listeningDecorator(existingExecutorService)
  2. submit(Callable<V>)方法ListeningExecutorService已缩小为返回 a ListenableFuture,它是 的子接口Future
  3. ListenableFuture有一个addListener()方法,因此您可以注册一个回调以在未来完成时运行。

回答by Subhrajyoti Majumder

ExecutorService#submitreturn FutureTask<T>which helps you to retrieve result and the ExecutorService#getmethod will block execution until the computation is not completed. Example -

ExecutorService#submitreturnFutureTask<T>帮助您检索结果,该ExecutorService#get方法将阻止执行,直到计算未完成。例子 -

ExecutorService executor = Executors.newFixedThreadPool(10);
Future<Long> future = executor.submit(new Callable<Long>(){
       @Override
       public Long call() throws Exception {
           long sum = 0;
           for (long i = 0; i <= 10000000l; i++) {
               sum += i;
           }
           return sum;
       }
});
Long result = future.get();
System.out.println(result);

回答by Gray

So, I was wondering if it's possible to attach a callback function to the event of a thread finishing using the ExecutorService.

所以,我想知道是否可以将回调函数附加到使用 ExecutorService 完成的线程的事件。

Not directly, no, but there are a couple of ways you could accomplish this. The easiest way that comes to mind is to wrap your Runnablein another Runnablethat does the reaping of the results.

不直接,不,但有几种方法可以实现这一点。想到的最简单的方法是将您的方法包装Runnable在另一个Runnable可以收获结果的方法中。

So you'd do something like:

所以你会做这样的事情:

threadPool.submit(new ResultPrinter(myRunnable));
...

private static class ResultPrinter implements Runnable {
    private final MyRunnable myRunnable;
    public ResultPrinter(MyRunnable myRunnable) {
        this.myRunnable = myRunnable;
    }
    public void run() {
        myRunnable.run();
        Results results = myRunnable.getResults();
        // print results;
    }
}

回答by Max

You can add a callback for when a thread returns in Java 8+ using CompletableFutureas in the following, where tis the result of your long-running computation,

您可以在 Java 8+ 中添加一个线程在 Java 8+ 中返回时的回调,CompletableFuture如下所示,其中t是长时间运行的计算结果,

CompletableFuture.supplyAsync(() -> {
    T t = new T();
    // do something
    return t;
}).thenApply(t -> {
    // process t
});

If you want to use callbacks in just Java 7, you could do something like,

如果你只想在 Java 7 中使用回调,你可以这样做,

int x = 10;
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(x);
Future<T> result = fixedThreadPool.submit(() -> {
    // do calculation
    return T;
});
fixedThreadPool.submit(() -> {
    long minutesToWait = 5;
    T t = null;
    try {
        t = result.get(minutesToWait, TimeUnit.MINUTES);
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
        LOGGER.error(e);
    }
    if (t != null) {
        // process t
    }
});