You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/12/08 13:56:22 UTC

groovy git commit: Achieve fine-grained concurrent access to classCache

Repository: groovy
Updated Branches:
  refs/heads/master 384ee1c44 -> 8815f3ea0


Achieve fine-grained concurrent access to classCache


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/8815f3ea
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/8815f3ea
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/8815f3ea

Branch: refs/heads/master
Commit: 8815f3ea028e0dee13ee319c584613daa7c8947b
Parents: 384ee1c
Author: sunlan <su...@apache.org>
Authored: Fri Dec 8 21:56:06 2017 +0800
Committer: sunlan <su...@apache.org>
Committed: Fri Dec 8 21:56:06 2017 +0800

----------------------------------------------------------------------
 src/main/groovy/lang/GroovyClassLoader.java | 54 ++++++++++++++++++------
 1 file changed, 41 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/8815f3ea/src/main/groovy/lang/GroovyClassLoader.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/lang/GroovyClassLoader.java b/src/main/groovy/lang/GroovyClassLoader.java
index af01538..7333129 100644
--- a/src/main/groovy/lang/GroovyClassLoader.java
+++ b/src/main/groovy/lang/GroovyClassLoader.java
@@ -72,6 +72,7 @@ import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * A ClassLoader which can load Groovy classes. The loaded classes are cached,
@@ -89,13 +90,17 @@ import java.util.Map;
  * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
  */
 public class GroovyClassLoader extends URLClassLoader {
-
     private static final URL[] EMPTY_URL_ARRAY = new URL[0];
+    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
 
     /**
      * this cache contains the loaded classes or PARSING, if the class is currently parsed
      */
-    protected final Map<String, Class> classCache = new HashMap<String, Class>();
+    protected final Map<String, Class> classCache = new HashMap<String, Class>(); // TODO should we make classCache private?
+
+    private final ReentrantReadWriteLock rwlForClassCache = new ReentrantReadWriteLock();
+    private final ReentrantReadWriteLock.ReadLock readLockForClassCache = rwlForClassCache.readLock();
+    private final ReentrantReadWriteLock.WriteLock writeLockForClassCache = rwlForClassCache.writeLock();
 
     /**
      * This cache contains mappings of file name to class. It is used
@@ -614,8 +619,12 @@ public class GroovyClassLoader extends URLClassLoader {
      */
     protected Class getClassCacheEntry(String name) {
         if (name == null) return null;
-        synchronized (classCache) {
+
+        readLockForClassCache.lock();
+        try {
             return classCache.get(name);
+        } finally {
+            readLockForClassCache.unlock();
         }
     }
 
@@ -628,8 +637,13 @@ public class GroovyClassLoader extends URLClassLoader {
      * @see #clearCache()
      */
     protected void setClassCacheEntry(Class cls) {
-        synchronized (classCache) {
-            classCache.put(cls.getName(), cls);
+        String className = cls.getName();
+
+        writeLockForClassCache.lock();
+        try {
+            classCache.put(className, cls);
+        } finally {
+            writeLockForClassCache.unlock();
         }
     }
 
@@ -642,8 +656,11 @@ public class GroovyClassLoader extends URLClassLoader {
      * @see #clearCache()
      */
     protected void removeClassCacheEntry(String name) {
-        synchronized (classCache) {
+        writeLockForClassCache.lock();
+        try {
             classCache.remove(name);
+        } finally {
+            writeLockForClassCache.unlock();
         }
     }
 
@@ -1010,10 +1027,16 @@ public class GroovyClassLoader extends URLClassLoader {
      * @return all classes loaded by this class loader
      */
     public Class[] getLoadedClasses() {
-        synchronized (classCache) {
-            final Collection<Class> values = classCache.values();
-            return values.toArray(new Class[values.size()]);
+        final Collection<Class> values;
+
+        readLockForClassCache.lock();
+        try {
+            values = classCache.values();
+        } finally {
+            readLockForClassCache.unlock();
         }
+
+        return values.toArray(EMPTY_CLASS_ARRAY);
     }
 
     /**
@@ -1028,15 +1051,20 @@ public class GroovyClassLoader extends URLClassLoader {
      * @see #removeClassCacheEntry(String)
      */
     public void clearCache() {
-        Class<?>[] clearedClasses;
-        synchronized (classCache) {
-            clearedClasses = getLoadedClasses();
+        Collection<Class> classesToClear;
+
+        writeLockForClassCache.lock();
+        try {
+            classesToClear = classCache.values();
             classCache.clear();
+        } finally {
+            writeLockForClassCache.unlock();
         }
+
         synchronized (sourceCache) {
             sourceCache.clear();
         }
-        for (Class<?> c : clearedClasses) {
+        for (Class c : classesToClear) {
             // Another Thread may be using an instance of this class
             // (for the first time) requiring a ClassInfo lock and
             // classloading which would require a lock on classCache.