【问题标题】:How do uncaught exceptions behave in threads?未捕获的异常在线程中如何表现?
【发布时间】:2014-03-19 15:28:35
【问题描述】:

我试图了解一个程序发生了什么,其中我有异常“消失”而没有任何通知(并且线程停止工作)。

我能想出的重现该问题的最简单情况是:

(defn -main []
  (let [a (future (do (println "Ouch... ") 
                      (/ 0 0)
                      (println "We never arrive here")))]
      (Thread/sleep 1000)
      (println "Hmmmm" @a)))

果然,在 repl 上运行(或使用 lein run)时,我得到一个异常:

so.core> (-main)
Ouch... 
ArithmeticException Divide by zero  clojure.lang.Numbers.divide (Numbers.java:156)

这是我预期的行为。

但是现在如果我删除未来的取消引用:

(defn -main []
  (let [a (future (do (println "Ouch... ") 
                      (/ 0 0)
                      (println "We never arrive here")))]
      (Thread/sleep 1000)
      (println "Hmmmm")))

这是输出:

so.core> (-main)
Ouch... 
Hmmmm
nil
so.core> 

所以 future 被执行(否则 “Ouch...” 不会被打印)并且显然会抛出异常(否则 “我们永远不会到达这里” 会打印)...但是找不到那个异常,程序继续运行,好像一切都很好。

显然,只要我不尝试取消对未来的引用,线程就可以在它的工作中间默默地死掉(在这种情况下打印到标准输出),并且找不到异常。

这正常吗?

我是否应该在我的 Emacs / cider 缓冲区之一中找到该异常的(堆栈)跟踪?

什么是让未来完成其工作(例如使用队列中的消息)并在出现问题时“警告”我的惯用方式?

我应该将以后的每个调用都包装在 try/catch 块中吗?

我应该设置一个默认的未捕获异常处理程序吗?

我不应该使用未来运行“不间断”线程吗?

基本上,我对 Java/Clojure 的行为感到非常困惑,并且希望能够解释 为什么 它的行为方式以及 如何应该解决这个问题。

【问题讨论】:

    标签: exception exception-handling clojure future


    【解决方案1】:

    在 clojure 中,future 是一个宏,它产生一个具体化的java.util.concurrent.Future,并取消引用它调用Future.get 方法。该方法可以抛出一个ExecutionException,它表示线程中未捕获的异常。因此,如果您不取消引用,则不会调用 .get 并且您不会得到异常。

    clojure doc网站有源码,所以可以看到实际实现here

    如果您不想取消引用,我想您应该在线程中try/catch,并以您选择的任何方式处理。

    【讨论】:

    • 小点,但 Clojure 未来 未来,而不是包装。
    • 改进了答案,使其更具体
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 2011-09-26
    • 2010-12-27
    相关资源
    最近更新 更多