Java从ExecutorService设置回调

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

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

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

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

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

这样的事情可能吗?

如果使用Google Guava是一个选项,您可以通过以下方式使用ListenableFuture界面:

  1. 通过MoreExecutors.listeningDecorator(existingExecutorService)ExecutorService转换为ListeningExecutorService
  2. ListeningExecutorServicesubmit(Callable)方法已经缩小,以返回一个ListenableFuture ,它是Future的子接口。
  3. ListenableFuture有一个addListener()方法,因此您可以注册一个回调,以便在将来完成时运行。

ExecutorService#submit返回FutureTask ,它可以帮助您检索结果, ExecutorService#get方法将阻止执行,直到计算未完成。 示例 –

 ExecutorService executor = Executors.newFixedThreadPool(10); Future future = executor.submit(new Callable(){ @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); 

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

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

所以你要做的事情如下:

 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; } } 

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

 int x = 10; ExecutorService fixedThreadPool = Executors.newFixedThreadPool(x); CompletableFuture.supplyAsync(() -> { T t = new T(); // do something return t; }).thenApply(t -> { // process t } 

如果你想在Java 7中使用回调,你可以做类似的事情,

 int x = 10; ExecutorService fixedThreadPool = Executors.newFixedThreadPool(x); Future 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 } }); 

哎呀,刚刚在StackOverflow上找到答案:

线程终止时的Java ExecutorService回调

谢谢你的耐心!