当前位置: 首页 > 知识库问答 >
问题:

中断java线程运行nashorn脚本

韩智敏
2023-03-14

在下面的代码中,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");
    }
}

共有3个答案

太叔志文
2023-03-14

不幸的是,它不适用于简单的无限循环:while(true){}。我尝试了线程。取消() 不会导致线程退出。我希望在IntelliJ插件中运行脚本时能够做到万无一失,因为用户可能会犯错误,导致无限循环,从而挂起插件。

我发现在大多数情况下唯一有效的是线程。停止()。即使这样,对于这样的脚本也不起作用:

while(true) { 
   try { 
       java.lang.Thread.sleep(100); 
   } catch (e) {  
   } 
}

javascript捕获java。lang.ThreadDeath异常并继续。我发现,即使有几个线程,上面的示例也不可能中断。stop()一个接一个地发出。为什么要使用多个?希望其中一个能在异常处理代码中捕获线程并中止它。如果catch块中有像var i=“e”这样简单的东西需要处理,那么它就可以工作 这足以导致第二个线程。stop()结束它。

因此,这个故事的寓意是,在纳肖恩,没有一种html" target="_blank">安全可靠的方式来结束失控的剧本,但在大多数情况下,有一种方法是可行的。

我的实现发出一个Thread.interrupt(),然后礼貌地等待2秒钟线程终止,如果失败,则发出Thread.stop()两次。如果这不起作用,那么其他任何东西也不会起作用。

希望它能帮助人们省去数小时的实验,找到一种更可靠的方法来阻止nashorn失控的脚本,而不是希望正在运行的脚本能够配合线程。取消()。

薛经纶
2023-03-14

JavaScript(在Nashorn下)与Java一样,不会在紧密循环的中间响应中断。脚本需要轮询中断并自动终止循环,或者它可以调用一些检查中断的东西,并让中断异常传播。

你可能会认为Nashorn“只是在运行一个脚本”,应该立即中断它。这不适用,原因与Java中不适用的原因相同:异步中断有损坏应用程序数据结构的风险,基本上无法避免或从中恢复。

异步中断带来的问题与长期被弃用的线程相同。停止方法。本文件对此进行了解释,它是注释中链接的文件的更新版本。

Java线程原语弃用

另请参阅Goetz,Java实践中的并发,第7章,取消和关闭。

检查中断的最简单方法是调用线程。中断()。您可以很容易地从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();
    }
}

由于我们正在启动一个线程池,不妨将其设为一个计划线程池,以便我们可以将其用于脚本任务和超时。这样我们就可以避免TimerTimerTask,无论如何,它们大多被SchduledExecutorService替换。

处理和中断时通常的惯例是恢复中断位或让中断异常传播。(永远不要忽视中断。)由于中断循环可以被视为已经完成了中断的处理,因此这两种情况都不是必需的,只需让脚本正常退出就足够了。

这种重写还将大量工作从构造函数转移到了一个init()方法中。这可以防止实例从构造函数中泄漏到其他线程。在原始示例代码中没有明显的危险——事实上,几乎从来没有危险——但避免从构造函数中泄漏实例始终是一种很好的做法。

佘修为
2023-03-14

所以这是旧的,但我只是写了这篇文章,并认为这可能是有价值的分享。默认情况下,您无法停止Nashorn脚本的执行,。取消()线程。stop()线程。interrupt()什么都不做,但是如果您愿意付出一些努力,并且可以重写一些字节码,那么这是可以实现的。细节:

http://blog.getsandbox.com/2018/01/15/nashorn-interupt/

 类似资料:
  • 问题内容: 在下面的代码中,我使javascript在与主要线程不同的线程中运行。该脚本是一个无限循环,因此需要以某种方式终止。怎么样? 脚本开始运行后,调用.cancel()无效。但是,如果我在线程初始化之后立即调用.cancel(),它将终止它(注释行)。 问题答案: 与Java一样,JavaScript(在Nashorn下)也不会像Java那样在紧密循环中响应中断。该脚本需要轮询中断并自动终

  • 如果以下代码在多线程应用程序中可以工作,您可以帮助我吗。 这是我的Java脚本,将由Nashorn评估 这就是我创建脚本引擎的方式 在使用Testng进行测试时,此操作不会出现任何错误 测试结果1-请注意,有些数据是重复的 但是,如果我添加"并行=true"到@DataProvider我的脚本开始失败 测试结果2-请注意,重复一些数据,以表明相同的参考编号可能在测试过程中随机失败 有人可以确认我是

  • 我想在服务器上呈现d3图表。我有三个选择:节点、幻影和纳肖恩。 我更喜欢Nashorn,因为我的API是Scala Play,我不想管理另一个进程。(部署、加载、排队等) 所以现在我需要让JSDom在Nashorn中工作,这样D3将有一些东西可以渲染。 到目前为止,这是可行的,但我不知道如何添加jsdom

  • 问题内容: 您将如何依次执行三个线程?例如。线程1,线程2,线程3。不可能将一个线程的引用传递给另一个线程并从run()方法调用。 因此代码应如下所示: 并应该把 这可以通过使用ThreadPoolExecutor并使用阻塞队列来实现,但即使那样也不是可以接受的答案。 问题答案: 在java.util.concurrent包中使用ExecutorService。更精确地使用

  • 问题内容: 我有一个线程,需要每10秒执行一次。该线程包含对另一台服务器上的数据库的多次调用(12-15)。此外,它还可以访问大约3个文件。因此,将有大量的IO和网络开销。 执行上述操作的最佳策略是什么? 一种方法是将sleep方法与while循环一起使用,但这将是一个糟糕的设计。 在这种情况下,类似于Timer的类会有所帮助吗?另外,最好创建几个更多的线程(一个用于IO,一个用于JDBC),而不

  • 这个教程中,你会通过简单易懂的代码示例,来了解Nashorn JavaScript引擎。Nashorn JavaScript引擎是Java SE 8 的一部分,并且和其它独立的引擎例如Google V8(用于Google Chrome和Node.js的引擎)互相竞争。Nashorn通过在JVM上,以原生方式运行动态的JavaScript代码来扩展Java的功能。 在接下来的15分钟内,你会学到如何