0

我有一个长期运行的计算,我已经与Java 的ForkJoinTask.

JavaFutureTask提供了一个模板方法done()覆盖此方法允许“注册完成处理程序”

是否可以为 a 注册完成处理程序ForkJoinTask

我问是因为我不想在我的应用程序中有阻塞线程 - 但是一旦我通过调用result = ForkJoinPool.invoke(myForkJoinTask)or检索计算结果,我的应用程序就会有一个阻塞线程result = ForkJoinPool.submit(myForkJoinTask).get()

4

1 回答 1

1

我认为您的意思是“无锁”编程http://en.wikipedia.org/wiki/Non-blocking_algorithm?虽然 FutureTask.get() 可能会阻塞当前线程(从而留下空闲的 CPU),但 ForkJoinTask.get()(或连接​​)试图保持 CPU 忙碌。

如果您能够将问题拆分为许多小问题(ForkJoinTask),则此方法效果很好。如果一个 FJTask 在内部等待另一个尚未准备好的任务的结果,则 ForkJoinTask 会尝试从其 ForkJoinPool 中提取一些其他工作(任务)并同时执行该任务。

直到您的所有任务都受 CPU 限制,它才能正常工作:您所有的 CPU 都保持忙碌。如果您的任何任务等待某些外部事件(即向火星探测器发送 REST 调用),则它不起作用。问题也应该形成DAG,否则您可能会陷入僵局。但是,除非您只在同一个任务中加入之前分叉的任务,否则它运行良好。如果你最后加入你分叉的任务,那就更好了。

因此,在您的任务之内/之间调用 get() 或 join() 并不会太糟糕。

您提到了一个完成处理程序来解决问题。如果你自己实现 ForkJoinTask,你可以看看 RecursiveTask 甚至 RecursiveAction。您将实现 compute(),并且您可以轻松地将每个任务的结果转发到 compute() 函数末尾的某个收集器,而不是返回它。

但是你必须考虑到你的收集器会被同时调用!要添加值或计算完成计数,请查看java.util.concurrent.atomic。避免使用同步块。否则,您的所有任务都必须等待这个单一的瓶颈,并且只有一个 CPU 继续工作。

我认为传播结果比返回结果涉及更多问题(因为 FJPool 处理了这个问题)。此外,在什么时候完成最终结果变得难以决定(并与外界沟通)。

于 2013-10-09T14:49:35.060 回答