Java 高负载下Groovy Shell解释器中的锁争用
我们正在评估应用程序中用于动态执行标准Java语法的解释器(v2.4) 早些时候,我们使用Java BeanShell解释器,但它的负载很低,这促使我们寻找Groovy之类的替代品 示例Java代码Java 高负载下Groovy Shell解释器中的锁争用,java,multithreading,groovy,groovyshell,Java,Multithreading,Groovy,Groovyshell,我们正在评估应用程序中用于动态执行标准Java语法的解释器(v2.4) 早些时候,我们使用Java BeanShell解释器,但它的负载很低,这促使我们寻找Groovy之类的替代品 示例Java代码 static String script = "int y = x * x; System.out.println(\"** value of y ** :: \" + y ); "; GroovyShell gs = new GroovyShell(); Script evalScript =
static String script = "int y = x * x; System.out.println(\"** value of y ** :: \" + y ); ";
GroovyShell gs = new GroovyShell();
Script evalScript = gs.parse("void evalMethod() {" + script + "}");
// bind variables
Binding binding = new Binding();
binding.setVariable("x", 5);
evalScript.setBinding(binding);
// invoke eval method
evalScript.invokeMethod("evalMethod", null);
当多个线程同时执行上述代码时,我们会看到线程锁争用。我们有多个线程处于阻塞状态,这会降低应用程序性能
阻塞线程调用堆栈
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.ClassLoader.loadClass(ClassLoader.java:404)
- waiting to lock <0x00000007bc425e40> (a java.lang.Object)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:411)
- locked <0x00000007bd369ba8> (a groovy.lang.GroovyClassLoader)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:677)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:545)
at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:185)
at org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:170)
at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:126)
at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:676)
at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:313)
at org.codehaus.groovy.control.ResolveVisitor.transformPropertyExpression(ResolveVisitor.java:845)
at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:696)
at org.codehaus.groovy.control.ResolveVisitor.transformMethodCallExpression(ResolveVisitor.java:1081)
at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:702)
at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitExpressionStatement(ClassCodeExpressionTransformer.java:142)
at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:42)
at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:37)
at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:166)
at org.codehaus.groovy.control.ResolveVisitor.visitBlockStatement(ResolveVisitor.java:1336)
at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71)
at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:104)
at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:115)
at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitConstructorOrMethod(ClassCodeExpressionTransformer.java:53)
at org.codehaus.groovy.control.ResolveVisitor.visitConstructorOrMethod(ResolveVisitor.java:201)
at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:126)
at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1081)
at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:53)
at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1279)
at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:176)
at org.codehaus.groovy.control.CompilationUnit$12.call(CompilationUnit.java:663)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:943)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:605)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:554)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
- locked <0x00000007bd372240> (a java.util.HashMap)
at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
at groovy.lang.GroovyShell.parse(GroovyShell.java:736)
at groovy.lang.GroovyShell.parse(GroovyShell.java:727)
java.lang.Thread.State:已阻止(在对象监视器上)
位于java.lang.ClassLoader.loadClass(ClassLoader.java:404)
-等待锁定(java.lang.Object)
位于sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
位于java.lang.ClassLoader.loadClass(ClassLoader.java:411)
-锁定(groovy.lang.GroovyClassLoader)
位于groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:677)
位于groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:545)
位于org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:185)
位于org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:170)
位于org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:126)
位于org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:676)
位于org.codehaus.groovy.control.resolveisitor.resolve(resolveisitor.java:313)
位于org.codehaus.groovy.control.ResolveVisitor.transformPropertyExpression(ResolveVisitor.java:845)
位于org.codehaus.groovy.control.resolveisitor.transform(resolveisitor.java:696)
位于org.codehaus.groovy.control.ResolveVisitor.transformMethodCallExpression(ResolveVisitor.java:1081)
位于org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:702)
在org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitExpressionStatement上(ClassCodeExpressionTransformer.java:142)
访问org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:42)
位于org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:37)
位于org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:166)
位于org.codehaus.groovy.control.ResolveVisitor.visitBlockStatement(ResolveVisitor.java:1336)
访问org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71)
位于org.codehaus.groovy.ast.ClassCodeVisitorSupport.VisitClassClassClassClassCodeContainer(ClassCodeVisitorSupport.java:104)
位于org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitconstructormethod(ClassCodeVisitorSupport.java:115)
在org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitconstructormethod(ClassCodeExpressionTransformer.java:53)
位于org.codehaus.groovy.control.ResolveVisitor.VisitConstructorMethod(ResolveVisitor.java:201)
位于org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:126)
位于org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1081)
位于org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:53)
位于org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1279)
位于org.codehaus.groovy.control.resolveisitor.startResolving(resolveisitor.java:176)
位于org.codehaus.groovy.control.CompilationUnit$12.call(CompilationUnit.java:663)
位于org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:943)
位于org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:605)
位于org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:554)
位于groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
位于groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
-锁定(java.util.HashMap)
位于groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
位于groovy.lang.GroovyShell.parse(GroovyShell.java:700)
位于groovy.lang.GroovyShell.parse(GroovyShell.java:736)
位于groovy.lang.GroovyShell.parse(GroovyShell.java:727)
我的问题是:
Script
object。Script
对象线程安全吗?此外,我需要将变量绑定到Script
对象(通过groovyBinding
对象,这对于不同线程中的每次执行都是不同的),因此我认为缓存groovyScript
对象不是一个可行的选择groovy解析和编译是一个相当重要的部分 如果您的脚本是静态的,那么您只需解析它一次 如果脚本总是不同但重复,则可以将编译后的groovy脚本缓存到
ConcurrentHashMap<String, Class<groovy.lang.Script>>
只需将evalScript.getClass()
放入已编译脚本的缓存中
在gs.parse(…)
之前,请检查您是否编译了脚本,并仅获取缓存类的新实例(如果存在)
检查以下示例和执行速度
String script=“int y=x*x;System.out.println(\”**y的值**::\”+y);”;
def ts=System.currentTimeMillis()
对于(int i=0;iThanks!执行已编译脚本类实例的缓存(evalScript.getClass()
)是否会导致任何内存泄漏或生成的类和元类的清理延迟?如果脚本数量不限,则必须考虑清理缓存。您可以使用一些简单的方法来代替ConcurrentHashMap
:Collections.synchronizedMap(new WeakHashMap())
或内存缓存中的某些缓存或任何其他..请注意,这不是线程安全的。调用setBinding和invokeMethod unsynchroniz
Script evalScript = gs.parse(...);
String script = "int y = x * x; System.out.println(\"** value of y ** :: \" + y ); ";
def ts = System.currentTimeMillis()
for(int i=0;i<100;i++){
GroovyShell gs = new GroovyShell();
Script evalScript = gs.parse("void evalMethod() {" + script + "}");
// bind variables
Binding binding = new Binding();
binding.setVariable("x", i);
evalScript.setBinding(binding);
// invoke eval method
evalScript.invokeMethod("evalMethod", null);
}
println ">> ${System.currentTimeMillis() - ts} millis"
String script = "int y = x * x; System.out.println(\"** value of y ** :: \" + y ); ";
GroovyShell gs = new GroovyShell();
Class<Script> scriptClass = gs.parse("void evalMethod() {" + script + "}").getClass();
def ts = System.currentTimeMillis()
for(int i=0;i<100;i++){
Script evalScript = scriptClass.newInstance();
// bind variables
Binding binding = new Binding();
binding.setVariable("x", i);
evalScript.setBinding(binding);
// invoke eval method
evalScript.invokeMethod("evalMethod", null);
}
println ">> ${System.currentTimeMillis() - ts} millis"