Hi Joao, as you are overriding ThreadLocal.get(), the effect is that testJsFunction is simply eval()ed anew by every thread, so each thread creates its own closure. (I guess it’s never a good idea to override ThreadLocal.get() without calling super.get() at all …)
But anyway, the real problem I have is probably mutation of a closure. That’s possible if the closure is over a mutable object, like a HashMap. Closure mutation works both in the same thread: https://gist.github.com/jfrantzius/0a40c963413bdeabb51ecb13a769a436#file-nashornclosuretest-java-L138 As well as in another thread: https://gist.github.com/jfrantzius/0a40c963413bdeabb51ecb13a769a436#file-nashornclosuretest-java-L166 I guess my initial proposal of Nashorn performing some magical closure resolution with ThreadLocals is just bogus. I’ll go for dedicated global per thread, and as an optimization, I’ll pool them. Thanks for being helpful + cheers from Berlin, Jörg Am 20.02.2017 um 15:54 schrieb João Paulo Varandas <joaovaran...@inpaas.com<mailto:joaovaran...@inpaas.com>>: @Test public void testClosureThreadSafety() throws ScriptException { String testJsFunction = ( " (function outerFunction(currentThreadName) {\n" + " print(indx.incrementAndGet() + ' ' + java.lang.Thread.currentThread().toString() + ': closure data is ' + currentThreadName) \n" + " function innerFunction() {\n" + " return currentThreadName;\n" + " }\n" + " return innerFunction;\n" + " })(java.lang.Thread.currentThread().toString())\n"); e.getBindings(ScriptContext.GLOBAL_SCOPE).put("indx", new AtomicInteger(0)); ScriptObjectMirror jsFunction = (ScriptObjectMirror) e.eval(testJsFunction); String mainThreadName = Thread.currentThread().toString(); ThreadLocal<ScriptObjectMirror> innerjs = new ThreadLocal<ScriptObjectMirror>() { @Override public ScriptObjectMirror get() { try { return (ScriptObjectMirror) e.eval(testJsFunction); } catch(Exception e) { throw new RuntimeException(e); } } }; IntConsumer invokeAndTest = i -> { try { // my main closure is unchanged Assert.assertEquals(mainThreadName, jsFunction.call(jsFunction)); // since I have a new closure for each thread ... final ScriptObjectMirror innerJsFunction = innerjs.get(); final String currentThreadName = Thread.currentThread().toString(); Assert.assertEquals(currentThreadName, innerJsFunction.call(innerJsFunction)); } catch(Exception e) { throw new RuntimeException(e); } }; IntStream.range(0, 10).parallel().forEach(invokeAndTest); } --- Dipl. Inf. Jörg von Frantzius, Technical Director E-Mail joerg.frantz...@aperto.com Phone +49 30 283921-318 Fax +49 30 283921-29 Aperto GmbH – An IBM Company Chausseestraße 5, D-10115 Berlin http://www.aperto.com<http://www.aperto.de/> http://www.facebook.com/aperto https://www.xing.com/companies/apertoag HRB 77049 B, AG Berlin Charlottenburg Geschäftsführer: Dirk Buddensiek, Kai Großmann, Stephan Haagen, Daniel Simon