未捕获的异常如何在线程中表现?

Ced*_*tin 4 exception-handling future exception clojure

我试图了解一个程序正在发生什么,我有异常"消失"而没有任何通知(并且一个线程停止工作).

我能想出的最简单的问题是重现这个问题:

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

当然,当在repl(或使用lein run)运行时,我得到一个例外:

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

这是我期望的行为.

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

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

这是输出:

so.core> (-main)
Ouch... 
Hmmmm
nil
so.core> 
Run Code Online (Sandbox Code Playgroud)

因此未来将被执行(否则"哎哟..."将不会被打印)显然会抛出异常(否则"我们永远不会到达这里"会打印)......但是这个例外无处可寻找程序继续,好像一切都很好.

显然,只要我不尝试取消引用未来,线程就可以在其工作中间(在这种情况下打印到stdout)静默地死亡,并且无处可寻找异常.

这是正常的吗?

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

什么是让未来做其工作的惯用方法(例如,从队列中消费消息)并在出现问题时"警告"我?

我应该在try/catch块中包装每个未来的调用吗?

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

我不应该使用未来运行"不停止"的线程吗?

基本上,我是在Java/Clojure的,这里的行为很迷茫,想有两种解释,为什么它的行为这种方式和如何我应该解决这个问题.

Kev*_*vin 6

在clojure中future是一个生成reified的宏java.util.concurrent.Future,并且取消引用它会调用Future.get方法.该方法可以抛出ExecutionException,它表示线程中未捕获的异常.因此,如果你没有取消引用,你就不要打电话.get,你也不会得到例外.

clojure doc站点有源,所以你可以在这里看到实际的实现.

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