Java从ExecutorService设置回调
我有一个fixedThreadPool,我用它来运行一堆工作线程来实现具有许多组件的任务的并行执行。
当所有线程都完成后,我使用方法(getResult)检索它们的结果(相当大)并将它们写入文件。
最终,为了节省内存并能够看到中间结果,我希望每个线程在完成执行后立即将其结果写入文件,然后释放其内存。
通常,我会在run()方法的末尾添加代码。 但是,此类中的某些其他对象也会调用这些线程,但不要让它们将结果写入文件 – 而是使用其结果执行其他计算,最终将其写入文件。
所以,我想知道是否可以使用ExecutorService将回调函数附加到线程完成事件。 这样,我可以立即检索其结果并在该场景中释放内存,但在其他场景中使用这些线程时不会破坏代码。
这样的事情可能吗?
如果使用Google Guava是一个选项,您可以通过以下方式使用ListenableFuture界面:
- 通过
MoreExecutors.listeningDecorator(existingExecutorService)
将ExecutorService
转换为ListeningExecutorService -
ListeningExecutorService
的submit(Callable
方法已经缩小,以返回一个) ListenableFuture
,它是Future
的子接口。 -
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回调
谢谢你的耐心!