【问题标题】:ForkJoinTask completion handlerForkJoinTask 完成处理程序
【发布时间】:2013-09-02 03:21:21
【问题描述】:

我与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() 检索计算结果,我的应用程序就会有一个阻塞线程。

【问题讨论】:

  • "...我不想阻塞线程..." -- 请详细解释。如果您有多个线程,something 必须等待完成才能收集结果并对其进行处理。
  • On “如果你有多个线程,则必须等待完成才能收集结果并对其进行处理。”这种假设不正确,因为如果您有多个线程,您可以让每个线程将其结果放入某个同步或原子数据结构中,并检查每个线程是否完整数据,然后触发任何新活动而无需额外的“等待”并收集线程”。

标签: java promise future fork-join completionhandler


【解决方案1】:

我想你的意思是“无锁”编程http://en.wikipedia.org/wiki/Non-blocking_algorithm?虽然 FutureTask.get() 可能会阻塞当前线程(从而使 CPU 处于空闲状态),但 ForkJoinTask.get()(或 join)试图保持 CPU 忙碌。

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多