GroovyShell 线程安全 [英] GroovyShell Thread safety

查看:75
本文介绍了GroovyShell 线程安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该问题出现在有关 GroovyShell 的所有问题的评论中,例如 使用 GroovyShell 作为表达式评估器/引擎";(或:如何重用 GroovyShell).这并不奇怪,因为 API 的设计似乎根本没有涵盖这个主题.不幸的是,这从未被明确讨论过.

The question appears in comments of all questions about GroovyShell, like Using GroovyShell as "expression evaluator/engine" (or: How to reuse GroovyShell). Not a surprise, since the design of the API seems it's not covering this topic at all. Unfortunately, this was never discussed explicitly.

紧凑形式的问题:

静态初始化:

final GroovyShell shell = new GroovyShell();
final Script thisScript = shell.parse("sleep 1000; return input1+' '+input2");
//anotherScript = // not relevant here but my use-case pre-loads ~300 groovy scripts

脚本运行器:

private Object runScript(Script theScript, String param1, String param2) {
  theScript.setProperty("input1", param1);
  theScript.setProperty("input2", param2);
  Object result = theScript.run();
  return result;
}

序列化执行:

runScript(thisScript, "Hello", "World")   -> Hello World
runScript(thisScript, "Guten", "Tag")     -> Guten Tag

并行执行:

runScript(thisScript, "Hello", "World")   -> Guten Tag (!)
runScript(thisScript, "Guten", "Tag")     -> Guten Tag

问题在于绑定(无论是 get/setBinding 还是 setProperty)是在脚本级别完成的.这就像在通过 classLoader 加载或修改静态成员变量之后在加载的 java.lang.Class 对象上设置一些东西.是否有替代的 groovy 实现来处理绑定和作为原子操作运行?或者甚至更好:使用上下文对象来执行?

The problem is that the binding (no matter if get/setBinding or setProperty) is done on script level. That's like setting something on a loaded java.lang.Class object after loading it through the classLoader or modifying static member variables. Is there an alternative groovy implementation which handles binding and running as an atomic operation? Or even better: uses a context object for execution?

最简单的解决方法是将 runScript() 同步到脚本对象,但这不会扩展.

The simplest workaround is synchronizing runScript() to the script object but this doesn't scale.

推荐答案

创建脚本类的不同实例以并行运行它们.

create different instances of script class to run them in parallel.

GroovyShell shell = new GroovyShell();
Class<Script> scriptClass = shell.parse("sleep 1000; return input1+' '+input2").getClass();

Object runScript(Class<Script> clazz, String param1, String param2) {
    Script theScript = clazz.newInstance();
    theScript.setProperty("input1", param1);
    theScript.setProperty("input2", param2);
    Object result = theScript.run();
    return result;
}
//thread test
[
    ["111","aaa"],
    ["222","bbb"]
].collect{x->
    Thread.start{
        println "start $x"
        println runScript(scriptClass, x[0], x[1])
    }
}*.join()

输出:

start [111, aaa]
start [222, bbb]
111 aaa
222 bbb

这篇关于GroovyShell 线程安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆