[ https://issues.apache.org/jira/browse/GROOVY-8213?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16187338#comment-16187338 ]
Jochen Theodorou commented on GROOVY-8213: ------------------------------------------ when I spoke of a performance penalty, then I did not mean the pure field read, I did mean method inlining. If the method you are calling is guarded by a volatile check, then inlining will not happen.... unless hotspot changed here in the meantime. The expected effect of this change is for me that no inlining is going to happen anymore in purely dynamic Groovy without primopts, indy or compilestatic. So you may not notice immediately. But I would wish for a benchmark in this direction. And just to make the point more understandable.. I actually made such a test back before Groovy 1.8 and later for primitive optimizations. And got exactly that result. > Closures are maybe not Threadsafe > --------------------------------- > > Key: GROOVY-8213 > URL: https://issues.apache.org/jira/browse/GROOVY-8213 > Project: Groovy > Issue Type: Bug > Affects Versions: 2.4.10 > Environment: Gradle 3.5 > Reporter: Björn Kautler > Assignee: John Wagenleitner > Fix For: 2.4.13 > > > I just upgraded our Gradle build from 1.12 (including Groovy 1.8.6) to 3.5 > (including Groovy 2.4.10). > Now I get a very strange behavior for stuff that is there for years already > and it looks to me as if this is a Groovy bug, maybe a non-threadsafeness of > Closures. > I have a custom task that contains the following code: > {code} > def sourceFilesSize = getSourceFiles().files.size() > def poolSize = Runtime.runtime.availableProcessors() > def executor = new ThreadPoolExecutor(poolSize, poolSize, 0, SECONDS, > new ArrayBlockingQueue<Runnable>([sourceFilesSize, 1].max())) > def tasks = [] > inputs.outOfDate { toTransform -> > tasks.add executor.submit { > project.exec { > if (gscPath) { // here starts > com.empic.build.tasks.Ghostscript$_exec_closure8$_closure11 > environment 'GSC', gscPath > def tempDir = "$temporaryDir/${Thread.currentThread().name}" > project.file(tempDir).mkdirs() > environment 'TEMP', tempDir > } > executable executablePath > def arguments = [toTransform.file.absolutePath] > if ((sourceFilesSize == 1) && getDestinationFile()) { > arguments << getDestinationFile().absolutePath > } else if (destinationDirectory) { > arguments << new File(destinationDirectory, > fileNameMapping(toTransform.file.name)).absolutePath > } else { > arguments << new File(toTransform.file.parentFile, > fileNameMapping(toTransform.file.name)).absolutePath > } > args arguments // here ends > com.empic.build.tasks.Ghostscript$_exec_closure8$_closure11 > } > } > } > executor.shutdown() > executor.awaitTermination 1, HOURS > tasks*.get() // here is line 137 > {code} > When this task is executed e. g. with five source files, sometimes all works > fine, sometime the build fails with > {noformat} > ... > Caused by: java.util.concurrent.ExecutionException: > java.lang.IllegalStateException: initialize must be called for meta class of > class com.empic.build.tasks.Ghostscript$_exec_closure8$_closure11(class > org.codehaus.groovy.runtime.metaclass.ClosureMetaClass) to complete > initialisation process before any invocation or field/property access can be > done > at com.empic.build.tasks.Ghostscript.exec(Ghostscript.groovy:137) > at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73) > ... 80 more > Caused by: java.lang.IllegalStateException: initialize must be called for > meta class of class > com.empic.build.tasks.Ghostscript$_exec_closure8$_closure11(class > org.codehaus.groovy.runtime.metaclass.ClosureMetaClass) to complete > initialisation process before any invocation or field/property access can be > done > {noformat} > Actually I was not able to reproduce the problem locally, but if I run the > build on our CI server and attach a debugger, I indeed was able to reproduce > the problem with a relatively high reproduction rate. (as in every second to > third build approximately, opposed to once every 100 builds) > I logged the current thread when the {{initialized}} property is set to > {{true}} and when it is requested with non-suspending breakpoints, but this > seems to have caused the timing to change enough already that I was not able > to reproduce the error within approximately the first two dozens of tries. > I was able to successfully break at the throwing of the > {{IllegalStateException}} though. This happens in > {{groovy.lang.MetaClassImpl.checkInitalised}}. > The stacktrace at this point is: > {noformat} > "pool-2-thread-3@10709" prio=5 tid=0x47 nid=NA runnable > java.lang.Thread.State: RUNNABLE > at groovy.lang.MetaClassImpl.checkInitalised(MetaClassImpl.java:1647) > at > org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:257) > at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1027) > at groovy.lang.Closure.call(Closure.java:414) > at groovy.lang.Closure.call(Closure.java:408) > at groovy.lang.Closure.run(Closure.java:495) > at > java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) > at java.util.concurrent.FutureTask.run(FutureTask.java:266) > at > java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) > at > java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) > at java.lang.Thread.run(Thread.java:745) > {noformat} > with the closure for which we are at the {{ClosureMetaClass}} in the topmost > frame being the mentioned > {{com.empic.build.tasks.Ghostscript$_exec_closure8$_closure11}}. -- This message was sent by Atlassian JIRA (v6.4.14#64029)