我有很多Java字节码的例子,我想从Clojure执行所有这些例子。每个字节码序列可能包含一个无限循环,在这种情况下,我想在几秒钟后停止运行它。我一直在期待将期货作为一种手段。在寻找几个实现后,我尝试了这两个代码:
(deref (future (loop[a 1] (recur a)) :done!) 1000 :impatient!)
...还有https://gist.github.com/3124000
的代码在这两种情况下,循环似乎都是适当的超时(在后一种情况下,未来报告已完成和取消),但我看到我的CPU使用率上升到99%左右并保持不变。我还看到每次运行此代码时,我的Java进程都会获得额外的线程。
在我看来,未来正在取消,但代码仍在运行。在我的程序中,我将需要运行和超时,一些非常紧密的无限循环(例如,相当于“20 PRINT GOTO 10”的Java字节码),我没有选择修改我正在运行的代码。
为什么我看到这种行为的任何想法;我能做些什么来阻止它;还是替代方法让我实现了运行和超时这些代码的目标?
答案 0 :(得分:7)
Java支持的线程取消机制是interrupts。不推荐使用.stop()
方法是有原因的 - 请参阅the docs,Effective Java,Java Concurrency in Practice等。
事实上,FutureTask
(支持future-cancel
)的实施是基于中断的。
截至今天,每个Clojure未来都有一个无限制的线程池(就像send-off
个动作一样)。所以你可以利用线程中断原语:
(def worker
(let [p (promise)]
{:future (future
(let [t (Thread/currentThread)]
(deliver p t)
(while (not (Thread/interrupted))
(println 42)
(Thread/sleep 400))))
:thread @p}))
现在,您可以成功执行(.interrupt (:thread worker))
或(future-cancel (:future worker))
。
虽然这将线程取消机制与Futures的机制相结合,但可用的Executor实现足够智能,可以清除先前任务可能已设置的中断状态,因此对一个任务的中断不会影响其他任务 - 即使它们是在同一个线程上运行。
关键是先发制人地杀死线程通常是一个坏主意 - 如果你想取消任务,你必须以某种或其他方式明确地取消它们。 OTOH,在您的特定情况下,您正在执行不透明的字节码,因此除了诉诸.stop()
之外别无选择。
答案 1 :(得分:4)
我发现实际杀死在线程内执行的代码的唯一方法是使用不推荐使用的.stop
方法。在很多情况下,它被弃用的原因并不重要。
我在clojail中有一个功能就是这样做。随意抢夺功能或只是拉入图书馆。
答案 2 :(得分:1)
根据Java API文档,cancel
未被授予能够立即停止任务的权限。
尝试取消执行此任务。如果任务已完成,已取消或由于某些其他原因无法取消,则此尝试将失败。如果成功,并且在调用cancel时此任务尚未启动,则此任务永远不会运行。如果任务已经启动,则mayInterruptIfRunning参数确定执行此任务的线程是否应该在尝试停止任务时被中断。