同一线程多ScriptEngine实例是否共享引擎与全局上下文及多线程疑问
Nashorn ScriptEngine多线程问题答疑
问题背景
同一线程中的多个ScriptEngine实例是否共享同一个引擎和全局上下文?
我定义了如下两个类:
public class A { private static ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); private static Invocable invoker = null; private static Object obj = null; static { engine.eval("file.js"); invoker = (Invocable) engine; // 后续不再修改 obj = engine.get("ObjectName"); // 后续不再修改 // 异常捕获代码在此 } public static String method1(String[] args) { return invoker.invokeMethod(obj, "getValue", args[0], args[1]); } // 更多类似方法 } public class B { public static Object methodB() { ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); return engine.eval("Some js string + function"); // 动态变化 } }我对多线程概念较为陌生,针对上述代码存在以下疑问:
1. 类A中的engine是否会被所有线程共享,还是每个线程会拥有独立的engine对象?
- 类A里的
engine是用static修饰的成员变量,在Java中,static变量属于类本身,只会在类第一次加载时初始化一次。所以不管有多少线程调用类A的方法,所有线程都会共享这同一个engine实例,不会每个线程都生成独立的engine对象。
2. 类A和类B中的engine是否为同一个实例?即二者是否共享同一运行中的引擎?若是,是否也共享同一上下文?
- 完全不是同一个实例。类A的
engine是static变量,整个应用生命周期里只有这一个;而类B的methodB每次被调用时,都会通过new ScriptEngineManager().getEngineByName("nashorn")获取一个全新的ScriptEngine实例。 - 既然是不同的实例,它们自然不共享运行引擎和全局上下文,各自的变量、执行环境都是完全独立的,彼此之间不会产生任何干扰。
3. 若在执行engine.eval("file.js")后不再修改任何内部变量值,且仅调用函数(不对类A中的引擎进行全局变量的增删改操作),是否可认为该引擎是线程安全的?
- 先给你明确结论:不行。Nashorn ScriptEngine本身就不是线程安全的,哪怕你只做只读的函数调用也一样。因为引擎在执行函数时,内部会维护执行栈、临时状态等数据,多个线程同时调用的话,这些内部状态会被并发修改,很容易出现数据错乱、抛出异常甚至程序崩溃的情况。
- 哪怕你的函数完全无状态、不碰任何全局变量,也只是“可能”不出问题,但这属于侥幸行为——Java官方文档明确标注了ScriptEngine实例不能被多线程并发使用,绝对不要依赖这种不安全的场景。
4. 若从多个线程调用类A的method1方法,这些调用会同时/并发执行,还是引擎会逐个处理调用?
- 引擎本身不会做任何并发控制,多个线程的调用会尝试同时执行,但因为Nashorn引擎不是线程安全的,这种并发执行会直接导致内部状态冲突,大概率会出现各种异常或者错误的返回结果。
- 如果想让这些调用安全执行,你得自己加同步控制,比如在
method1方法上加synchronized关键字,或者用其他锁机制,保证同一时间只有一个线程在调用该引擎的方法,让调用排队逐个处理。
内容的提问来源于stack exchange,提问作者Kalai selvan
相关产品推荐
相关产品推荐

