自定义ExecutionContext中reportFailure方法作用及未触发问题咨询
首先来说reportFailure的实际作用:它是Scala的ExecutionContext用来处理未被任何代码捕获或处理的异常的兜底机制。当你通过ExecutionContext提交的任务(不管是Future内部的任务,还是直接调用execute提交的Runnable)抛出了异常,而且这个异常没有被后续的代码处理(比如没有给Future添加onFailure、recover这类回调,也没有通过Await主动获取异常),这时候reportFailure就会被调用,相当于给你一个机会记录或处理这些"漏网"的异常。
接下来分析为什么你的代码没有打印"ho ha ha...":
你在代码里用了Await.result(f, Duration.Inf),这个方法会主动获取Future的结果——如果Future失败了,它会把Future里的异常重新抛出到主线程中。换句话说,这个异常已经被Await.result"接手"并传播到了你的调用线程,不属于"未被处理"的异常,所以ExecutionContext不会触发reportFailure。
举个例子,修改你的代码,去掉Await.result,或者用以下方式提交任务,就能看到reportFailure被调用:
val myEc = new ExecutionContext { val tp = Executors.newFixedThreadPool(2) def execute(r: Runnable) { tp.submit(r) } def reportFailure(t: Throwable) { println("ho ha ha ... something broke!") } } // 场景1:直接提交一个抛异常的Runnable,没有任何代码处理异常 myEc.execute(new Runnable { override def run(): Unit = throw new Exception("直接执行的任务抛异常了") }) // 场景2:创建Future但不处理失败,也不Await结果 Future(throw new Exception("123"))(myEc) // 等待一下,让线程池有时间执行任务 Thread.sleep(1000)
这时候你就能看到控制台打印出"ho ha ha ... something broke!"了。
总结一下:reportFailure是处理那些完全无人问津的异常的,只要有代码主动获取并处理了Future的异常(比如Await、onFailure、recover),它就不会被触发。
内容的提问来源于stack exchange,提问作者Knows Not Much

