Scala:如何捕获子线程中的异常

时间:2017-05-07 13:21:46

标签: scala exception-handling

我原以为Try捕获了跨线程异常,如下例所示。我猜不是:那么如何在衍生的子线程中捕获异常?

// Simple class that throws error
class Child extends Runnable {
  def run {
    val exception: Exception = new Exception("Foo")
    val i = 1
    Thread.sleep(1000)
    val lines = scala.io.Source.fromFile("/tmp/filefoobar.txt").mkString
    Thread.sleep(1000)
  }
}
// spawn the class above
def Parent() = {
  val doit = Try {
    val t = new Thread(new Child)
    t.start
    t.join()
  }

  doit match {
    case Success(v) => println("uh oh did not capture error")
    case Failure(v) => println("good we caught the error")
  }
}

输出 阶>父()

Exception in thread "Thread-35" java.io.FileNotFoundException: /tmp/filefoobar.txt (No such file or directory)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at scala.io.Source$.fromFile(Source.scala:91)
    at scala.io.Source$.fromFile(Source.scala:76)
    at scala.io.Source$.fromFile(Source.scala:54)
    at $line120.$read$$iw$$iw$Child.run(<console>:16)
    at java.lang.Thread.run(Thread.java:745)
uh oh did not capture error

3 个答案:

答案 0 :(得分:3)

考虑使用Futures来处理异步任务的结果

import ExecutionContext.Implicits.global
val resultFuture: Future[Unit] = Future { new Child.run }
resultFuture.onComplete (result: Try[Unit] => ...)

答案 1 :(得分:0)

当子进程访问该文件时会引发异常,该异常捕获JRE并遵循默认行为;打印堆栈跟踪,然后将异常传播到父进程,这会捕获您在输出中看到的Parent。

你可以做的是在子进程中捕获异常并抛出异常,以便父进程可以处理它。

答案 2 :(得分:0)

您可以使用Thread.setUncaughtExceptionHandler设置例外,然后从try:

重新抛出它
import java.lang.Thread.UncaughtExceptionHandler

def Parent() = {

  @volatile
  var maybeException: Option[Throwable] = None

  val doit = Try {
    val target = new Child
    val t = new Thread(target)
    t.setUncaughtExceptionHandler(new UncaughtExceptionHandler {
      override def uncaughtException(t: Thread, th: Throwable): Unit = {
        maybeException = Some(th)
      }
    })
    t.start()
    t.join()

    maybeException.foreach(th => throw th)
  }

  doit match {
    case Success(v) => println("uh oh did not capture error")
    case Failure(v) => println("good we caught the error")
  }
}