我有一个长期运行的计算,我已将其与Java's ForkJoinTask
分开。
Java's FutureTask
提供了一种模板方法done()
。 Overriding this method allows for "registering a completion handler"。
是否可以为ForkJoinTask
注册完成处理程序?
我在问,因为我不想在我的应用程序中使用阻塞线程 - 但只要通过调用result = ForkJoinPool.invoke(myForkJoinTask)
或result = ForkJoinPool.submit(myForkJoinTask).get()
检索计算结果,我的应用程序就会有阻塞线程
答案 0 :(得分:1)
我认为你的意思是“锁定免费”编程http://en.wikipedia.org/wiki/Non-blocking_algorithm?虽然FutureTask.get()可能阻塞当前线程(因此留下一个空闲的CPU),但ForkJoinTask.get()(或join)会尝试使CPU保持忙碌状态。
如果你能够将你的问题分成许多小小的和平(ForkJoinTask),这种方法很有效。如果一个FJTask在内部等待另一个未准备好的任务的结果,那么ForkJoinTask会尝试从其ForkJoinPool中获取其他一些工作(Task),并同时执行该任务。
直到你的所有任务都受CPU限制,它才能正常工作:你的所有CPU都保持忙碌状态。 如果您的任何任务等待某些外部事件(即向火星探测器发送REST呼叫),它将不起作用。问题也应该形成DAG,否则你可能会陷入僵局。但是,在你加入之前在同一个任务中分叉的任务之前,它运行良好。如果你加入你最后分叉的任务,那就更好了。
因此,在任务中/之间调用get()或join()并不会太糟糕。
您提到了一个解决问题的完成处理程序。如果您自己实现ForkJoinTask,可以查看RecursiveTask甚至RecursiveAction。您将实现compute(),您可以轻松地将每个任务的结果转发到compute()函数末尾的某个收集器,而不是返回它。
但你必须考虑到你的收藏家会同时被召唤!要添加值或计算完成次数,请查看java.util.concurrent.atomic。避免使用同步块。否则,您的所有任务都必须等待这个单一瓶颈,并且只有一个CPU继续工作。
我认为传播结果涉及的问题多于返回它们(因为FJPool处理这个问题)。此外,很难决定(并与外界沟通)您的最终结果。