Reputation: 167
I had thought that the Try
catches cross-Thread exceptions as in example below. I guess not: so how do I catch exceptions in spawned child threads?
// 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")
}
}
Output scala> Parent()
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
Upvotes: 5
Views: 1755
Reputation: 4017
Consider using Futures to handle result of async task
import ExecutionContext.Implicits.global
val resultFuture: Future[Unit] = Future { new Child.run }
resultFuture.onComplete (result: Try[Unit] => ...)
Upvotes: 6
Reputation: 2733
You can use Thread.setUncaughtExceptionHandler
to set the exception and then rethrow it from the 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")
}
}
Upvotes: 0
Reputation: 195
When the child accesses to the file raises an exception which captures JRE and follows the default behaviour; print stack trace, then propagates exception to parent processes, which captures the Parent as you can see in your output.
What you could do is catching the exception in the child process and throw yourself the exception so the parent could handle it.
Upvotes: 0