Just for reference...this seems to be https://stackoverflow.com/questions/45578426/lock-contention-in-groovy-shell-interpreter-under-high-load

more inline

On 09.08.2017 18:58, Aman Jain wrote:
Hello,

We are evaluating GroovyShell <http://groovy-lang.org/download.html> interpreter (v2.4) in our application for dynamically executing standard Java syntax.

Earlier, we were using Java BeanShell Interpreter for it, but it has an issue <https://stackoverflow.com/questions/45450947/lock-contention-in-java-beanshell-interpreter-under-high-load/45451768#45451768> under high load which prompted us to look for an alternative such as Groovy.

We are seeing thread lock contention when multiple threads execute the below sample code simultaneously. We have multiple threads in the blocked state which is degrading application performance.

I am missing the counter part, the one that owns the lock. but looking at

    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)

my strong assumption would be, that the counter part is also in java.lang.ClassLoader. My guess would be, that we are currently trying to load a class, probably from some other thread. If you have code like

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);

you would with each thread execution do a new compilation, which is where the majority of those class look-ups is coming from. The script form example contains System, which will be looked-up in maybe 10 variants before the compiler is happy. That makes 9 false look-ups. Multiply this with a hundred threads and you get 900 look-ups for classes, that actually do not exist. So the goal would be reuse. My suggestion would be then:

for all threads:

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 + "}");

in each thread:

// bind variables
Binding binding = new Binding();
binding.setVariable("x", 5);
Script threadEvalScript = InvokerHelper.createScript(evalScript.getClas(), binding);
// invoke eval method
threadEvalScript.invokeMethod("evalMethod", null);

Even better would be of course to make a pool of script instances and use them from there


My questions are:

 1. Has anyone experienced such problem? If yes, can you please suggest
    any possible resolution for it? I googled around for this problem
    and few blogs suggested to cache groovy |Script| object. Is
    |Script| object thread-safe? Moreover, I need to bind variables to
    |Script|object (via groovy |Binding| object, which is different for
    each execution in different threads), so I don't think caching
    groovy |Script| object is a viable option.

You have to understand that there is the script and the binding. Ideally the script itself stores all the state in the binding. Then you need one combination of script and binding per thread that is concurrently running. How you can do that I tried to show above already a bit.

btw, Binding is not thread-safe, but nothing prevents you from implementing your own Binding, that is. But given your statement, that the Binding is different each time I do not think there is a problem with this.

 2. Are there any best practices that I need to follow while using
    Groovy Shell interpreter with Java?

Biggest problem normally is the delayed clean-up of the generated classes and meta classes, but this should not concern you here, once you managed to reuse the script class.

bye Jochen

Reply via email to