Rhino和对javax.script.ScriptEngine的并发访问
我通过Rhino和对javax.script.ScriptEngine的并发访问,java,javascript,rhino,Java,Javascript,Rhino,我通过javax.scriptAPI使用Rhino 1.6r2。我知道Rhino引擎声称“引擎实现在内部是线程安全的,脚本可以并发执行,尽管脚本在一个线程上执行的效果可能对其他线程上的脚本可见。” 我想知道的是,在什么样的确切条件下,一个脚本执行的效果对另一个脚本执行是可见的?在我的代码中,我有时会重复使用ScriptEngine对象,但每次执行时,我都会创建一个新的SimpleBindings,并将其传递给eval(String,Bindings)。有了这种安排,内部状态是否有可能从一个执行泄
javax.script
API使用Rhino 1.6r2。我知道Rhino引擎声称“引擎实现在内部是线程安全的,脚本可以并发执行,尽管脚本在一个线程上执行的效果可能对其他线程上的脚本可见。”
我想知道的是,在什么样的确切条件下,一个脚本执行的效果对另一个脚本执行是可见的?在我的代码中,我有时会重复使用ScriptEngine
对象,但每次执行时,我都会创建一个新的SimpleBindings
,并将其传递给eval(String,Bindings)
。有了这种安排,内部状态是否有可能从一个执行泄漏到另一个执行?如果是,怎么做
是的,JSR223没有指定脚本语言中的变量应该如何与给定的
绑定绑定。因此,实现者完全有可能选择在引擎实例中存储全局范围变量,并在评估脚本时重用它,即使给定不同的绑定
例如,JRuby的JSR223绑定有一种模式是以这种方式工作的
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
public class Jsr223Binding {
private Jsr223Binding() throws ScriptException {
System.setProperty("org.jruby.embed.localvariable.behavior", "transient");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("jruby");
ScriptContext ctx1 = new SimpleScriptContext();
ScriptContext ctx2 = new SimpleScriptContext();
engine.eval("$foo = 5\nputs $foo", ctx1);
engine.eval("puts $foo", ctx2);
}
public static void main(String[] args) throws ScriptException {
new Jsr223Binding();
}
}
script包是线程安全的,但如果您的脚本不是线程安全的,则可能会出现并发问题。
脚本中的全局变量对所有线程都可见。因此,避免在javascript函数中使用全局变量
我现在遇到了这个问题。我的javascript如下所示:
function run(){
regex = 0;
regex += 1;
return regex;
}
我在线程池中运行它(4)10000次,并打印结果
for (int i = 0; i <= 10000; i++){
executor.submit(new Runnable() {
@Override
public void run() {
try {
Double result = (Double) invocable.invokeFunction("run");
System.out.println(result);
} catch (Exception e) {}
}
});
}
我修改了答案,以表明如果在eval()函数中指定上下文,rhino脚本引擎的执行是完全线程安全的。此示例同时从5个不同线程调用javascript函数100次:
package samplethread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
public class JSRunner {
private static final ScriptEngine engine;
private static final ScriptEngineManager manager;
private static final String script = "function fibonacci(num){\r\n" +
" var a = 1, b = 0, temp;\r\n" +
"\r\n" +
" while (num >= 0){\r\n" +
" temp = a;\r\n" +
" a = a + b;\r\n" +
" b = temp;\r\n" +
" num--;\r\n" +
" }\r\n" +
"\r\n" +
" return b;\r\n" +
"} \r\n" +
"var out = java.lang.System.out;\n" +
"n = 1;" +
"while( n <= 100 ) {" +
" out.println(java.lang.Thread.currentThread().getName() +':'+ 'FIB('+ n +') = ' + fibonacci(n));" +
" n++;" +
" if (java.lang.Thread.interrupted()) {" +
" out.println('JS: Interrupted::'+Date.now());" +
" break;" +
" }" +
"}\n";
static {
manager = new ScriptEngineManager();
engine = manager.getEngineByName("JavaScript");
}
public static void main(final String... args) throws Exception {
for(int i = 0;i<5;i++) {
try {
final Bindings b = engine.createBindings();
final SimpleScriptContext sc = new SimpleScriptContext();
sc.setBindings(b, ScriptContext.ENGINE_SCOPE);
execWithFuture(engine, script,sc);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
private static void execWithFuture(final ScriptEngine engine, final String script,final ScriptContext sc) throws Exception {
System.out.println("Java: Submitting script eval to thread pool...");
ExecutorService single = Executors.newSingleThreadExecutor();
Callable<String> c = new Callable<String>() {
public String call() throws Exception {
String result = null;
try {
engine.eval(script,sc);
} catch (ScriptException e) {
result = e.getMessage();
}
return result;
}
};
single.submit(c);
single.shutdown();
System.out.println("Java: ...submitted.");
}
}
package-samplethread;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入javax.script.Bindings;
导入javax.script.ScriptContext;
导入javax.script.ScriptEngine;
导入javax.script.ScriptEngineManager;
导入javax.script.ScriptException;
导入javax.script.SimpleScriptContext;
公共类JSRunner{
私有静态脚本引擎;
私有静态最终脚本引擎管理器;
private static final String script=“函数fibonacci(num){\r\n”+
变量a=1,b=0,临时;\r\n“+
“\r\n”+
“while(num>=0){\r\n”+
“temp=a;\r\n”+
“a=a+b;\r\n”+
“b=temp;\r\n”+
“num——;\r\n”+
“}\r\n”+
“\r\n”+
“返回b;\r\n”+
“}\r\n”+
“var out=java.lang.System.out;\n”+
“n=1;”+
“一会儿(n你是在绑定同一个对象吗?如果我绑定同一个对象进行多次执行,那么显然所有人都可以看到。但不,我没有这么做。那么你到底想弄清楚什么?如果你对不同的绑定对象使用不同的绑定,你还关心哪些状态?@wort-I是t暗示更多由脚本创建或修改的状态,而不是从Java传递到脚本中。如果我在脚本中声明一个全局变量,该变量的范围是什么?如果我修改某个内置全局变量会发生什么?这些是由javax.script API指定的,还是由引擎实现者指定的?这是您正在寻找的吗对于?您所说的根本不是真的。如果为同一脚本引擎实例创建单独的脚本上下文,并指定适当的范围(引擎范围),则不会出现此问题。
package samplethread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
public class JSRunner {
private static final ScriptEngine engine;
private static final ScriptEngineManager manager;
private static final String script = "function fibonacci(num){\r\n" +
" var a = 1, b = 0, temp;\r\n" +
"\r\n" +
" while (num >= 0){\r\n" +
" temp = a;\r\n" +
" a = a + b;\r\n" +
" b = temp;\r\n" +
" num--;\r\n" +
" }\r\n" +
"\r\n" +
" return b;\r\n" +
"} \r\n" +
"var out = java.lang.System.out;\n" +
"n = 1;" +
"while( n <= 100 ) {" +
" out.println(java.lang.Thread.currentThread().getName() +':'+ 'FIB('+ n +') = ' + fibonacci(n));" +
" n++;" +
" if (java.lang.Thread.interrupted()) {" +
" out.println('JS: Interrupted::'+Date.now());" +
" break;" +
" }" +
"}\n";
static {
manager = new ScriptEngineManager();
engine = manager.getEngineByName("JavaScript");
}
public static void main(final String... args) throws Exception {
for(int i = 0;i<5;i++) {
try {
final Bindings b = engine.createBindings();
final SimpleScriptContext sc = new SimpleScriptContext();
sc.setBindings(b, ScriptContext.ENGINE_SCOPE);
execWithFuture(engine, script,sc);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
private static void execWithFuture(final ScriptEngine engine, final String script,final ScriptContext sc) throws Exception {
System.out.println("Java: Submitting script eval to thread pool...");
ExecutorService single = Executors.newSingleThreadExecutor();
Callable<String> c = new Callable<String>() {
public String call() throws Exception {
String result = null;
try {
engine.eval(script,sc);
} catch (ScriptException e) {
result = e.getMessage();
}
return result;
}
};
single.submit(c);
single.shutdown();
System.out.println("Java: ...submitted.");
}
}