我可以在 JAVA 中超时后终止 Runnable 吗?


ScriptEngineManager scriptEngineMgr = new ScriptEngineManager();
ScriptEngine jsEngine = scriptEngineMgr.getEngineByName("nashorn");
Mono.fromRunnable(() -> {
System.out.println("11111");
try {
System.out.println("2222");
jsEngine.eval("print("hello");while(1);");
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("3333");
}).timeout(Duration.ofMillis(2000)).doOnError(Exception.class, e -> {
System.out.println("4444");
System.out.println(e.toString());
}).onErrorResume(Exception.class, e -> {
System.out.println("5555");
return Mono.error(e);
}).block();
System.out.println("end!!!");

这段代码永远不会结束。 它显示"java.util.concurrent.TimeoutException:在 2000 毫秒内未在"source(MonoRunnable("中观察到任何项目或终端信号(并且未配置回退( ".

我想在 2 秒内终止它,然后看到"结束!!"。

如何解决这个问题?

这是对 reactor 的一个相当奇怪的用法 - 如果你真的想在 2 秒后超时,那么更正常/更好的方法可能是在新线程中生成你的eval(),并在一段时间后interrupt()该线程(然后根据需要处理InterruptedException

但是,要直接回答这个问题,您在链末端的onErrorResume()调用本身正在返回一个Mono.error(本质上是它正在处理的相同错误Mono的克隆。当您调用block()时,将引发此异常。

相反,您可能希望返回Mono.empty(),而不是在该onErrorResume()块中Mono.error(e)

我这样嘟囔着。但我不确定这是一个好方法。 我正在等待更好的主意。

ScriptEngineManager scriptEngineMgr = new ScriptEngineManager();
ScriptEngine jsEngine = scriptEngineMgr.getEngineByName("nashorn");
String script = "$result.test = 1;nwhile(1);";
Thread th = new Thread(() -> {
jsEngine.put("$result", new JSONObject());
try {
jsEngine.eval(script);
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
Mono.defer(() -> {
th.start();
try {
th.join();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return Mono.just(true);
}).timeout(Duration.ofSeconds(2)).doOnError(TimeoutException.class, e -> {
// e.printStackTrace();
System.out.println(th.isAlive());
th.stop();
}).doAfterTerminate(() -> {
System.out.println(result);
System.out.println("end!!!");
System.out.println(th.isAlive());
}).onErrorReturn(false).block();

最新更新