如何解决GroovyShell线程安全
该问题出现在有关GroovyShell的所有问题的注释中,例如Using GroovyShell as "expression evaluator/engine" (or: How to reuse GroovyShell)。不足为奇,因为API的设计似乎根本没有涵盖此主题。不幸的是,从未对此进行明确讨论。
简洁的问题:
静态初始化:
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,"World") -> Guten Tag (!)
runScript(thisScript,"Tag") -> Guten Tag
问题在于绑定(无论是get / setBinding还是setProperty)都在脚本级别完成。这就像通过classLoader加载了java.lang.Class对象或修改静态成员变量之后,对其进行了设置。是否有替代的常规实现将绑定和运行作为原子操作来处理?甚至更好:使用上下文对象执行?
最简单的解决方法是将runScript()
同步到脚本对象,但这不会扩展。
解决方法
创建脚本类的不同实例以并行运行它们。
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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。