因此,我运行了实验,Rhino引擎报告“Mozilla Rhino”是多线程的,JavaDocs断言
“多线程” - 引擎实现在内部是线程安全的,脚本可以并发执行,尽管脚本执行对一个线程的影响可能对其他线程上的脚本可见。
下面是代码...对我来说,它看起来是线程安全的,只要你传入的绑定也是线程安全的。
package org.rekdev;
import java.util.*;
import javax.script.*;
public class JavaScriptWTF {
public static void main( String[] args ) {
ScriptEngineManager mgr = new ScriptEngineManager();
List<ScriptEngineFactory> factories = mgr.getEngineFactories();
for ( ScriptEngineFactory factory : factories ) {
System.out.println( String.format(
"engineName: %s, THREADING: %s",
factory.getEngineName(),
factory.getParameter( "THREADING" ) ) );
}
}
}
...输出是...
引擎名称: AppleScriptEngine, THREADING: null
engineName: Mozilla Rhino, THREADING: MULTITHREADED
要回答您的确切问题...
绑定应该是线程安全的吗?
在我看来,你有责任使它们成为线程安全的。换句话说,只传入不可变对象,引擎是否线程安全就不再是问题。
是否应该允许多个线程共享一个 ScriptEngine 实例?
在我看来,他们似乎可以做到,但关键是通过绑定可以发生的状态共享。不可变对象是你的朋友。
...还是每个线程都应该构造一个短期实例?
在我看来,思考这个问题的最好方法是,eval的每次执行都是一个短暂的实例。
...还是把它们放在游泳池里?
在这个时代,试图自己汇集资源很少是一个好主意。给短期实例一个机会,测量其性能,然后从那里开始计算。
如果多个线程同时调用 ScriptEngine.eval(...) 会发生什么情况?
如果我正确地理解了Rhino引擎对多线程的回复,ScriptEngine.eval应该可以处理并发调用。
对于CompiledScript实例
,JavaDocs指出“在引擎随后执行脚本时,由编译脚本的执行引起的脚本引擎状态的变化可能会可见。http://docs.oracle.com/javase/6/docs/api/javax/script/CompiledScript.html。因此,在您似乎试图最小化ScriptEngine实例数量的环境中,它们听起来根本不是线程安全的。
对于使用 Invocable.getInterface(...) 生成的接口实现,也存在同样的问题?你在这里独自一人。我不明白为什么或何时会使用这种能力,在我看来,你可能在这里“跳过鲨鱼”。如果你想深入研究脚本语言,我建议你放弃JavaScript,看看Groovy,寻找一个更具脚本化的Java。
据推测,放置在Bindings中的对象遵循Java的垃圾回收。对最终不在绑定中的对象进行垃圾回收怎么办?
如果它们最终没有绑定,我希望它们绑定到ScriptEngine并遵循其生命周期(基于我阅读的文档)。池化 ScriptEngine 实例听起来不是一个好主意。