在下面的代码中,我使javascript在与主要线程不同的线程中运行。该脚本是一个无限循环,因此需要以某种方式终止。怎么样?
脚本开始运行后,调用.cancel()无效。但是,如果我在线程初始化之后立即调用.cancel(),它将终止它(注释行)。
package testscriptterminate;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.Timer;
import java.util.TimerTask;
public class TestScriptTerminate extends TimerTask{
private ExecutorService threads;
private Future runScript;
private Timer t;
public TestScriptTerminate(){
t = new Timer();
t.schedule(this, 6000); //let the script run for a while before attempt to cancel
threads = Executors.newFixedThreadPool(1);
runScript = threads.submit(new ScriptExec());
//runScript.cancel(true); //will cancel here, before the script had a change to run, but useless, i want to cancel at any time on demand
}
@Override
public void run(){
//after script has fully initialized and ran for a while - attempt to cancel.
//DOESN'T WORK, thread still active
System.out.println("Canceling now...");
runScript.cancel(true);
}
public static void main(String[] args) {
new TestScriptTerminate();
}
}
class ScriptExec implements Runnable{
private ScriptEngine js;
private ScriptEngineManager scriptManager;
public ScriptExec(){
init();
}
@Override
public void run() {
try {
js.eval("while(true){}");
} catch (ScriptException ex) {
System.out.println(ex.toString());
}
}
private void init(){
scriptManager = new ScriptEngineManager();
js = scriptManager.getEngineByName("nashorn");
}
}
与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()
方法中。这样可以防止实例从构造函数中泄漏到其他线程。在原始示例代码中,没有明显的危险-
实际上,几乎没有危险-但是,避免从构造函数中泄漏实例始终是一种好习惯。
在下面的代码中,javascript运行在与主线程不同的单独线程中。该脚本是一个无限循环,因此需要以某种方式终止。怎样 使命感脚本开始运行后,cancel()不起作用。但如果我打电话。cancel()在线程初始化之后,它将终止它(注释掉的行)。
我正在使用Java8 Nashorn来执行一个特定的先前同意的方法。我可以毫无问题地调用特定的方法。不过困扰我的一件事是,当我加载脚本时,它也会执行它。 例如,如果file.js包含一个print("hello world!")scriptEngine.eval(new FileReader("./file.js")将执行并打印hello world。我必须先这样做,然后才能调用我想要的特定方法。
问题内容: 我通过JSR 223使用Nashorn来执行用户输入脚本的小片段: 不同的用户脚本会调用在静态中央库(在上面的代码片段的String中保留)中定义的JavaScript函数。 每次我想获得可以从Java调用的an时,我总是不得不重新编译大型库代码。 有什么方法可以将以前编译的代码与新代码结合在一起? 问题答案: 这是由JSR-223设计的;后面真的没有代码缓存。嗯,从 理论上讲 可以,
我有一个类实例,上面有一个字段。我在对象上设置了这个实例。我需要在Nashorn中设置字段,以便在Java中调用。我该如何在Nashorn脚本中设置此字段? 脚本是这样调用的: 在脚本中,我需要在全局对象上设置字段: 我已经看到了(建议重复)如何使用Nashorn引擎调用Java对象的问题,但这个问题是关于从Nashorn脚本调用Java方法,而这个问题是关于在Nashorn脚本中设置一个可调用的
问题内容: 我想从下面的程序中运行一个shell脚本,但它似乎无能为力。我已经直接在linux终端中运行了相同的命令,它运行正常,所以我猜这是我的Java代码。如您所见,我首先使用PrintWriter将命令写入Shell脚本,但我希望这不会影响Shell脚本本身的运行。任何帮助,将不胜感激! 问题答案: 您应该使用返回的结果。 将命令作为单独的进程执行,并返回类型为的对象。您应该调用以便程序等待
我在尝试从Java运行R脚本时遇到了一个问题。我真的在互联网上寻找这个问题的答案,但什么都不管用。 求你帮帮我 这是java代码 以下是当我添加Runtime.getRuntime(). exec("Rcript"rScriptFileName)时抛出的错误消息: