[ 
https://issues.apache.org/jira/browse/GROOVY-8213?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul King closed GROOVY-8213.
-----------------------------

> 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
>            Priority: Major
>             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
(v7.6.3#76005)

Reply via email to