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

我应该为每个线程使用单独的ScriptEngine和CompiledScript实例吗?

苏星宇
2023-03-14

我的程序使用Java脚本API,可以同时评估一些脚本。它们不使用共享脚本对象、绑定或上下文,但可以使用相同的ScriptEngineCompiledScript对象。我发现Java8中的OracleNashorn实现不是多线程的,ScriptEngineFactory。getParameter('THREADING')返回null,文档中说:

引擎实现不是线程安全的,不能用于在多个线程上并发执行脚本。

这是否意味着我应该为每个线程创建一个单独的ScriptEngine实例?此外,文档中没有提到CompiledScript并发使用,而是:

每个已编译脚本都与一个脚本引擎相关联

可以假设CompiledScript线程安全依赖于相关的ScriptEngine,即我应该为Nashorn的每个线程使用单独的CompiledScript实例。

如果应该的话,对于这种(我认为非常常见的)情况,使用ThreadLocal、池或其他什么合适的解决方案是什么?

final String script = "...";
final CompiledScript compiled = ((Compilable)scriptEngine).compile(script);
for (int i=0; i<50; i++) {
    Thread thread = new Thread () {
        public void run() {
            try {
                scriptEngine.eval(script, new SimpleBindings ());  //is this code thread-safe?
                compiled.eval(new SimpleBindings ());  //and this?
            }
            catch (Exception e)  {  throw new RuntimeException (e);  }
        }
    };
    threads.start();
}

共有3个答案

柴华灿
2023-03-14

公认的答案会误导许多人。

简而言之:

  • NashornScriptEngine不是线程安全的
  • 如果不使用全局绑定,则无状态部分可以是线程安全的
井学
2023-03-14

ScriptEnginefor Nashorn不是线程安全的。这可以通过调用ScriptEngineFactory.get参数("THREADING")来验证。

返回的值为null,根据java文档,这意味着不是线程安全的。

注意:这部分答案首先在这里给出。但是我自己重新检查了结果和文档。

这也为我们提供了CompiledScript的答案。根据java文档,一个CompiledScript与一个ScriptEngine相关联。

所以在NashornScriptEngineCompiledScript中不应该被两个线程同时使用。

池永长
2023-03-14

您可以跨线程共享ScriptEngineCompiledScript对象。它们是线程安全的。实际上,您应该共享它们,因为一个引擎实例是类缓存和JavaScript对象隐藏类的持有者,所以只有一个引擎实例可以减少重复编译。

不能共享的是绑定对象。bindings对象基本上对应于JavaScript运行时环境的全局对象。引擎以默认绑定实例启动,但如果在多线程环境中使用它,则需要使用引擎。createBindings()为每个线程获取一个单独的绑定对象——它自己的全局对象,并将编译后的脚本计算到其中。这样,您将使用相同的代码设置独立的全局作用域。(当然,您也可以将它们集中在一起,或者在它们上进行同步,只要确保在一个绑定实例中工作的线程不超过一个即可)。在将脚本计算到绑定中后,可以随后高效地调用它用((JSObject)绑定定义的函数。获取(fnName)。打电话(这个,args…)

如果必须跨线程共享状态,那么至少尝试使其不可变。如果对象是不可变的,那么最好将脚本计算为单个绑定实例,然后跨线程使用它(希望调用没有副作用的函数)。如果它是可变的,则必须同步;要么是整个绑定,要么也可以使用var syncFn=Java。synchronized(fn,lockObj)Nashorn特定的JS API,以获取在特定对象上同步的JS函数版本。

这假定您在多个线程之间共享单个绑定。如果您想让多个绑定共享对象的子集(例如,将同一个对象放入多个绑定中),那么您必须以某种方式确保自己对共享对象的访问是线程安全的。

至于THREADING返回null的参数:是的,最初我们计划不让引擎线程安全(说语言本身不是线程安全的),所以我们选择了null值。我们现在可能需要重新评估这一点,正如我们在这期间所做的那样,引擎实例是线程安全的,只是全局范围(绑定)不是(而且永远不会是,因为JavaScript语言语义)

 类似资料:
  • 问题内容: 我的程序使用Java Scripting API,并且可以同时评估某些脚本。他们不使用共享脚本对象,绑定或上下文,但可以使用和对象。我看到,在Java的甲骨文8实施犀牛不是多线程的,回报率约该文件说: 引擎实现不是线程安全的,并且不能用于在多个线程上同时执行脚本。 这是否意味着我应该为每个线程创建一个单独的实例?此外,文档没有说明并发使用,而是: 每个CompiledScript与一个

  • 我写了以下代码: 我只使用了一个useState在一个对象中存储“name”、“link”、“error”等属性。因为我想将FormObj和ValidateLink的逻辑保持在一起。所有三个属性仅使用一个useEffect。因此,我认为最好将所有三个属性都保留在useState中,而不是创建3个不同的useState。 但是我的经理和技术架构师告诉我要为每个属性创建3个useState,一个use

  • 问题内容: 我打算使用Kubernetes和Ingress进行负载平衡。我正在尝试学习如何设置Flask,uWSGI和Nginx。我看到本教程将所有三个安装在同一容器中,我想知道是否应该使用它。 https://ianlondon.github.io/blog/deploy-flask-docker- nginx/ 我猜测将它们作为单独的容器和单独的容器的好处是它们可以分别进行单独缩放? 但是,F

  • 给stackoverflow社区的人们。我正在寻找一些帮助,以解决HikariCP连接池面临的问题。 高级:我正在尝试使用线程池创建多个线程,我的计划是为每个工作线程提供独立于HikariCP的连接,但HikariCP所做的是在多个线程之间共享一个公共连接。我正在使用 以检索DB连接。现在,当我关闭一个连接时,我在其他线程中看到问题,说连接关闭了,线程正在处理的批次记录被丢弃。 以下是我的日志文件

  • 我是否需要为我的复杂Web应用程序使用单独的Docker容器,或者我可以将所有必需的服务放在一个容器中?有人能解释一下为什么我应该将我的应用程序划分为许多容器(例如容器,容器,容器)当我能够在一个容器中安装和启动所有东西时?

  • 问题内容: 添加索引的开销有据可查,但是我无法找到有关何时使用各种索引的各种信息,这些信息与要建立索引的各种文档类型有关。 这是一个通用示例来说明问题: 说我们有以下实体 产品(名称,ProductID,ProductCategoryID,商店列表) 产品类别(名称,ProductCategoryID) 商店(名称,商店ID) 我是否应该将这三种不同类型的文档转储到一个索引中,每个索引都具有适当的