我已经使用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()
检索计算结果,我的应用程序就会具有阻塞线程。
最佳答案
我认为您是指“无锁”编程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处理了此问题)。另外,很难决定(并与外界沟通)完成最终结果的时间。