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(
