You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Björn Kautler (JIRA)" <ji...@apache.org> on 2019/08/06 13:53:00 UTC
[jira] [Commented] (GROOVY-8213) Closures are maybe not Threadsafe
[ https://issues.apache.org/jira/browse/GROOVY-8213?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16901077#comment-16901077 ]
Björn Kautler commented on GROOVY-8213:
---------------------------------------
[~jwagenleitner] are you sure this is fixed?
According [to the last comment in the Gradle issue you mentioned|https://github.com/gradle/gradle/issues/1420#issuecomment-431588379],
this also happened with Gradle 4.10.2 which includes Groovy 2.4.15.
I cannot say whether behavior changed for me as I outsourced the problematic code into a Java file to work-around this issue.
> 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.14#76016)