[
https://issues.apache.org/jira/browse/GROOVY-7535?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16012546#comment-16012546
]
Jochen Kemnade commented on GROOVY-7535:
----------------------------------------
It's the other case that makes the difference and that leads to the error, the
one where the other thread sets the value to 0 even though the current thread
is still using a category.
I think John's explanation shows the problem pretty well, so I'll rather show
you another possible way to fix the issue:
{code}
diff --git a/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
b/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
index 4c36935df..42533a5f7 100644
--- a/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
+++ b/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
@@ -72,7 +72,9 @@ public class GroovyCategorySupport {
private Map<String, String> propertySetterMap;
private void newScope () {
+ synchronized(atomicCategoryUsageCounter){
categoriesInUse = atomicCategoryUsageCounter.incrementAndGet();
+ }
DefaultMetaClassInfo.setCategoryUsed(true);
VMPluginFactory.getPlugin().invalidateCallSites();
level++;
@@ -95,7 +97,9 @@ public class GroovyCategorySupport {
}
}
level--;
+ synchronized(atomicCategoryUsageCounter){
categoriesInUse = atomicCategoryUsageCounter.decrementAndGet();
+ }
VMPluginFactory.getPlugin().invalidateCallSites();
if (categoriesInUse==0)
DefaultMetaClassInfo.setCategoryUsed(false);
if (level == 0) {
{code}
This would also fix the problem that the modification of the {{AtomicInteger}}
and the assignment of its current value to the {{int}} field are two separate
steps.
The problem is not that the other thread will not have changed the
{{AtomicInteger}} incorrectly but that it will have assigned an outdated value
to the {{int}} field.
bq. As for The ThreadLocal... well.. try it out. The speed was horrible last
time I tried
yes, I guessed so. Well, if we remove the {{AtomicInteger}} from the PR
version, the will effectively have the same semantics as if we were using a
{{ThreadLocal}}.
> Groovy category throwing MissingMethodException and MissingPropertyException
> when using multiple threads
> --------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-7535
> URL: https://issues.apache.org/jira/browse/GROOVY-7535
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 2.3.11, 2.4.4
> Environment: I have been able to reproduce this issue on a Cent O/S
> version 6.4 with Java 64 Bit JDK 1.8 and groovy 2.4.4.
> Reporter: James Oswald
> Assignee: Pascal Schumacher
> Fix For: 2.4.6
>
> Attachments:
> 0001-GROOVY-7535-fix-race-condition-between-the-modificat.patch,
> CategoryTest.groovy, exceptionForCategoryTest.txt,
> exceptionForTimeCategoryTest.txt, Test.groovy, TimeCategoryTest.groovy
>
>
> When using groovy use block, we randomly get
> groovy.lang.MissingPropertyException when trying to access a property off a
> category. (Attached is an example)
> {quote}
> index 76
> Exception in thread "Thread-77" groovy.lang.MissingPropertyException: No such
> property: millisecond for class: java.lang.Integer
> at
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:51)
> at
> org.codehaus.groovy.runtime.callsite.PojoMetaClassGetPropertySite.callGetProperty(PojoMetaClassGetPropertySite.java:43)
> at
> TimeCategoryTest$__spock_initializeFields_closure1$_closure4$_closure5.doCall(TimeCategoryTest.groovy:23)
> at
> TimeCategoryTest$__spock_initializeFields_closure1$_closure4$_closure5.doCall(TimeCategoryTest.groovy)
> at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> at java.lang.reflect.Method.invoke(Method.java:497)
> at
> org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
> at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
> at
> org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
> at
> groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
> at groovy.lang.Closure.call(Closure.java:423)
> at groovy.lang.Closure.call(Closure.java:417)
> at
> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:109)
> at
> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.access$400(GroovyCategorySupport.java:65)
> at
> org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:249)
> at
> org.codehaus.groovy.runtime.DefaultGroovyMethods.use(DefaultGroovyMethods.java:403)
> {quote}
> or groovy.lang.MissingMethodException when trying to access a method from a
> category.
> {quote}
> index 82
> Exception in thread "Thread-207" groovy.lang.MissingMethodException: No
> signature of method: java.lang.String.test() is applicable for argument
> types: (java.lang.String) values: [ bar]
> Possible solutions: next(), toSet(), getAt(java.lang.String), wait(). trim(),
> toList()
> at
> org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:56)
> at
> org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:46)
> at
> org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:122)
> at
> CategoryTest$__spock_initializeFields_closure1$_closure5.doCall(CategoryTest.groovy:24)
> at
> CategoryTest$__spock_initializeFields_closure1$_closure5.doCall(CategoryTest.groovy)
> at sun.reflect.GeneratedMethodAccessor12.invoke(Unknown Source)
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> at java.lang.reflect.Method.invoke(Method.java:497)
> at
> org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
> at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
> at
> org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
> at
> groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
> at groovy.lang.Closure.call(Closure.java:423)
> at groovy.lang.Closure.call(Closure.java:417)
> at
> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:109)
> at
> org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.access$400(GroovyCategorySupport.java:65)
> at
> org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:249)
> at
> org.codehaus.groovy.runtime.DefaultGroovyMethods.use(DefaultGroovyMethods.java:403)
> {quote}
> On the server, either one of these exceptions to appear every few days or
> weeks.
> I found a similar issue GROOVY-2105 which contains a test that reproduces
> this problem on Linux. Looking back the fix that was implemented for this
> ticket was to add synchronized to 3 methods. These changes were late removed
> in a refactor of GroovyCategorySupport.
> I have attached 3 test cases that reproduce the threading issue.
> NOTE: problem does not happen 100% of the time as it is a threading and
> timing issue, so you may have to play with the number of threads to generate
> the exception. What I have attached generates the exception on my linux box
> most of the time.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)