在ForkJoinPool任务/操作中处理未捕获异常的更好方法

时间:2012-02-02 03:30:07

标签: java multithreading java-7 java.util.concurrent fork-join

使用ForkJoinPool提交任务(RecursiveActionRecursiveTask)时处理异常(未捕获)的更好方法是什么?

当WorkerThread突然终止(无论如何不在我们的控制之下)时,ForkJoinPool接受Thread.UncaughtExceptionHandler来处理异常,但当ForkJoinTask抛出异常时不使用此处理程序。我在实施中使用标准submit / invokeAll方式。

以下是我的情景:

我有一个Thread在无限循环中运行,从第三方系统读取数据。在此线程中,我将任务提交到ForkJoinPool

new Thread() {
      public void run() {
         while (true) {
             ForkJoinTask<Void> uselessReturn = 
                   ForkJoinPool.submit(RecursiveActionTask);
         }
      }
 }

我正在使用RecursiveAction,在少数情况下使用RecursiveTask。这些任务使用submit()方法提交给FJPool。 我希望有一个类似于UncaughtExceptionHandler的通用异常处理程序,如果一个Task抛出一个未经检查/未捕获的异常,我可以处理异常并在需要时重新提交任务。处理异常还可确保在一个/某些任务抛出异常时排队的任务不会被取消。

invokeAll()方法返回一组ForkJoinTasks,但这些任务位于递归块中(每个任务调用compute()方法,可以进一步拆分[假设场景])

class RecursiveActionTask extends RecursiveAction {

    public void compute() {
       if <task.size() <= ACCEPTABLE_SIZE) {
          processTask() // this might throw an checked/unchecked exception
       } else {
          RecursiveActionTask[] splitTasks = splitTasks(tasks)
          RecursiveActionTasks returnedTasks = invokeAll(splitTasks);
          // the below code never executes as invokeAll submits the tasks to the pool 
          // and the flow never comes to the code below.
          // I am looking for some handling like this
          for (RecusiveActionTask task : returnedTasks) {
             if (task.isDone()) {
                task.getException() // handle this exception
             }
          }
       }
    }

}

我注意到当3-4个任务失败时,整个队列提交单元被丢弃。目前我已经在我个人不喜欢的过程任务中添加try/catch。我正在寻找更通用的。

  1. 我还想了解失败的所有任务列表,以便我可以重新提交
  2. 当任务抛出异常时,线程会从池中逐出(尽管我的分析发现它们没有[但不确定])?
  3. 在FutureTask上调用get()方法更有可能使我的流顺序等待任务完成。
  4. 我想知道任务失败时的状态。我不在乎什么时候完成(显然不想等一小时)
  5. 如何处理上述场景中的异常?

1 个答案:

答案 0 :(得分:2)

这表明我们在Akka解决了这个问题:

/**
 * INTERNAL AKKA USAGE ONLY
 */
final class MailboxExecutionTask(mailbox: Mailbox) extends ForkJoinTask[Unit] {
  final override def setRawResult(u: Unit): Unit = ()
  final override def getRawResult(): Unit = ()
  final override def exec(): Boolean = try { mailbox.run; true } catch {
    case anything ⇒
      val t = Thread.currentThread
      t.getUncaughtExceptionHandler match {
        case null ⇒
        case some ⇒ some.uncaughtException(t, anything)
      }
      throw anything
  }
 }