我曾经多次举例说明期货中的例外很难追查(并且已经在这里问了一个问题,为什么有些例外似乎永远不会发生,这个问题不是我老问题的愚蠢)并决定了尝试设置“默认未捕获的异常处理程序”。
然而,我无法使其发挥作用。我尝试使用reify,我尝试使用代理。就好像什么都没发生一样。
这是一个重现问题的最小案例:
REPL> (Thread/setDefaultUncaughtExceptionHandler
(proxy [Thread$UncaughtExceptionHandler] []
(uncaughtException [thread throwable]
(do (println (-> throwable .getCause .getMessage))
; (error "whatever...") ; some 'timbre' logging if you have timbre
))))
nil
REPL> (future (do (Thread/sleep 100) (/ 0 0)))
#<core$future_call$reify__6267@c2909a1: :pending>
REPL>
我尝试了 println ,我尝试使用音色记录到文件,我试图吐出一个临时文件,我试图通过deref'ing来强制将来运行...显然永远不会调用默认的未捕获异常处理程序。
有人能给我看一个实际捕获异常的工作默认未捕获异常处理程序的交互式/ REPL示例吗?
作为一个额外的问题:一旦设置了默认的未捕获异常处理程序,是否有一种简单的方法来“看到”它被设置?当您测试该功能并多次调用setDefaultUncaughtExceptionHandler时,REPL会发生什么?是否只考虑了最后一个处理程序?
答案 0 :(得分:1)
期货不太像这样。例外不会逃脱。
(deref (future (do (Thread/sleep 100) (/ 0 0))))
ExecutionException java.lang.ArithmeticException: Divide by zero
java.util.concurrent.FutureTask.report (FutureTask.java:122)
java.util.concurrent.FutureTask.get (FutureTask.java:192)
clojure.core/deref-future (core.clj:2108)
clojure.core/future-call/reify--6267 (core.clj:6308)
clojure.core/deref (core.clj:2128)
Java的FutureTask.run()的核心是答案......
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
这为最终消费者的未来回应节省了问题。如果我们稍微重构测试用例,我们可以清楚地看到异常处理程序工作:
(Thread/setDefaultUncaughtExceptionHandler
(proxy [Thread$UncaughtExceptionHandler] []
(uncaughtException [thread throwable]
(do (println "****" (-> throwable .getMessage))
))))
我删除了getCause,因为我们没有一个...
(.start (Thread. #(/ 0 0)))
stdout的收益率......
**** Divide by zero
如果你所有人(正如你的评论所建议的那样)是一个带有适当异常处理程序的线程,你是否考虑过以下内容:
(defn exception-safe-queue-reader [source sink]
(try
(let [message (source)]
(sink message))
(catch Throwable t
(println "****" t))
(recur source sink))
这对我来说是比使用uEH更标准的Java习惯 - 即如果你要处理错误,那么直接在你的代码中处理它们。无论是使用裸Java线程还是将来启动它都无关紧要。