与Java一样,Javascript(在Nashorn下)也不会像Java那样在紧密循环中响应中断。该脚本需要轮询中断并自动终止循环,或者可以调用一些检查中断并
InterruptedException传播的内容。
您可能会认为Nashorn在“只是运行脚本”,应该立即中断它。这并不适用,原因与在Java中不适用的原因相同:异步中断可能会损坏应用程序的数据结构,并且基本上没有办法避免它或从中恢复。
异步中断会带来与早已弃用的
Thread.stop方法相同的问题。本文档对此进行了说明,它是注释中链接的文档的更新版本。
Java线程原始弃用
另请参阅Goetz,《 Java并发实践》 ,第7章, 取消和关闭 。
检查中断的最简单方法是致电
Thread.interrupted()。您可以从Javascript很容易地调用它。这是对示例程序的重写,该示例程序在五秒钟后取消了正在运行的脚本:
public class TestscriptTerminate { ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); void script() { scriptEngineManager scriptManager = new scriptEngineManager(); scriptEngine js = scriptManager.getEngineByName("nashorn"); try { System.out.println("script starting."); js.eval("while (true) { if (java.lang.Thread.interrupted()) break; }"); System.out.println("script finished."); } catch (scriptException ex) { ex.printStackTrace(); } } void init() throws Exception { Future<?> scriptTask = pool.submit(this::script); pool.schedule(() -> { System.out.println("Canceling now..."); scriptTask.cancel(true); }, 5, TimeUnit.SECONDS); pool.shutdown(); } public static void main(String[] args) throws Exception { new TestscriptTerminate().init(); }}由于我们正在启动线程池,因此最好将其设置为预定的线程池,以便我们可以将其用于脚本任务和超时。这样,我们可以避免
Timer和
TimerTask,
ScheduledExecutorService无论如何大多数情况下,它们都会被替换。
处理和中断时通常的惯例是恢复中断位或进行
InterruptedException传播。( 永远不要
忽略中断。)由于可以认为中断循环已经完成了对中断的处理,所以两者都没有必要,而且看起来只要让脚本正常退出就足够了。
这种重写还将大量工作从构造函数移到了
init()方法中。这样可以防止实例从构造函数中泄漏到其他线程。在原始示例代码中,没有明显的危险-
实际上,几乎没有危险-但是,避免从构造函数中泄漏实例始终是一种好习惯。



