You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2011/06/13 07:36:09 UTC

svn commit: r1135027 - /river/jtsk/trunk/src/net/jini/loader/pref/PreferredClassProvider.java

Author: peter_firmstone
Date: Mon Jun 13 05:36:09 2011
New Revision: 1135027

URL: http://svn.apache.org/viewvc?rev=1135027&view=rev
Log:
River-396 Christopher Dolan's patch for PreferredClassProvider concurrency

Modified:
    river/jtsk/trunk/src/net/jini/loader/pref/PreferredClassProvider.java

Modified: river/jtsk/trunk/src/net/jini/loader/pref/PreferredClassProvider.java
URL: http://svn.apache.org/viewvc/river/jtsk/trunk/src/net/jini/loader/pref/PreferredClassProvider.java?rev=1135027&r1=1135026&r2=1135027&view=diff
==============================================================================
--- river/jtsk/trunk/src/net/jini/loader/pref/PreferredClassProvider.java (original)
+++ river/jtsk/trunk/src/net/jini/loader/pref/PreferredClassProvider.java Mon Jun 13 05:36:09 2011
@@ -43,6 +43,8 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.WeakHashMap;
@@ -274,7 +276,7 @@ public class PreferredClassProvider exte
      * references, so this table does not prevent loaders from being
      * garbage collected.
      */
-    private final Map loaderTable = new HashMap();
+    private final Map<LoaderKey,LoaderEntryHolder> loaderTable = new HashMap<LoaderKey,LoaderEntryHolder>();
 
     /** reference queue for cleared class loader entries */
     private final ReferenceQueue refQueue = new ReferenceQueue();
@@ -1556,31 +1558,55 @@ public class PreferredClassProvider exte
 	 * }
 	 */
 
+	/*
+	 * Take this opportunity to remove from the table entries
+	 * whose weak references have been cleared.
+	 */
+	List<LoaderKey> toRemove = new LinkedList<LoaderKey>();
+	Object ref;
+	while ((ref = refQueue.poll()) != null) {
+	    if (ref instanceof LoaderKey)
+		toRemove.add((LoaderKey) ref);
+	    else if (ref instanceof LoaderEntry) {
+		LoaderEntry entry = (LoaderEntry) ref;
+		if (!entry.removed)	// ignore entries removed below
+		    toRemove.add(entry.key);
+	    }
+	}
+
+	LoaderKey key = new LoaderKey(urls, parent);
+	LoaderEntryHolder holder;
 	synchronized (loaderTable) {
-	    /*
-	     * Take this opportunity to remove from the table entries
-	     * whose weak references have been cleared.
-	     */
-	    Object ref;
-	    while ((ref = refQueue.poll()) != null) {
-		if (ref instanceof LoaderKey) {
-		    LoaderKey key = (LoaderKey) ref;
-		    loaderTable.remove(key);
-		} else if (ref instanceof LoaderEntry) {
-		    LoaderEntry entry = (LoaderEntry) ref;
-		    if (!entry.removed) {	// ignore entries removed below
-			loaderTable.remove(entry.key);
-		    }
-		}
+	    if (!toRemove.isEmpty()) {
+		for (LoaderKey oldKey : toRemove)
+		    loaderTable.remove(oldKey);
+		toRemove.clear();
 	    }
 
 	    /*
 	     * Look up the codebase URL path and parent class loader pair
 	     * in the table of RMI class loaders.
 	     */
-	    LoaderKey key = new LoaderKey(urls, parent);
-	    LoaderEntry entry = (LoaderEntry) loaderTable.get(key);
+	    holder = loaderTable.get(key);
+	    if (null == holder) {
+		holder = new LoaderEntryHolder();
+		loaderTable.put(key, holder);
+	    }
+	}
 
+	/*
+	 * Four possible cases:
+	 *   1) this is our first time creating this classloader
+	 *      - holder.entry is null, need to make a new entry and a new loader
+	 *   2) we made this classloader before, but it was garbage collected a long while ago
+	 *      - identical to case #1 and it was reaped by the toRemove code above
+	 *   3) we made this classloader before, and it was garbage collected recently
+	 *      - holder.entry is non-null, but holder.entry.get() is null, very similar to case #1
+	 *   4) we made this classloader before, and it's still alive (CACHE HIT)
+	 *      - just return it
+	 */
+	synchronized (holder) {
+	    LoaderEntry entry = holder.entry;
 	    ClassLoader loader;
 	    if (entry == null ||
 		(loader = (ClassLoader) entry.get()) == null)
@@ -1593,7 +1619,6 @@ public class PreferredClassProvider exte
 		 * from the weak reference queue.
 		 */
 		if (entry != null) {
-		    loaderTable.remove(key);
 		    entry.removed = true;
 		}
 
@@ -1623,7 +1648,7 @@ public class PreferredClassProvider exte
 		 * weak reference and store it in the table with the key.
 		 */
 		entry = new LoaderEntry(key, loader);
-		loaderTable.put(key, entry);
+		holder.entry = entry;
 	    }
 	    return loader;
 	}
@@ -1737,6 +1762,9 @@ public class PreferredClassProvider exte
 	    this.key = key;
 	}
     }
+    private class LoaderEntryHolder {
+	public LoaderEntry entry;
+    }
 
     private static ClassLoader getClassLoader(final Class c) {
 	return (ClassLoader) AccessController.doPrivileged(