From f5a0517ac704b36e3d94aa3d5547ddf95889ab95 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 31 Jan 2014 07:36:16 +0100 Subject: JNLPClassLoader: Introduce pending removal of cached CLs (1 min) to enhance performance for single applet reload. --- .../sourceforge/jnlp/runtime/JNLPClassLoader.java | 52 +++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java index f889161..b4cd315 100644 --- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java @@ -123,11 +123,17 @@ public class JNLPClassLoader extends URLClassLoader { private boolean isSignedJNLP = false; /** map from JNLPFile unique key to shared classloader */ - private static Map uniqueKeyToLoader = new ConcurrentHashMap(); + private static final Object uniqueKeyMapLock = new Object(); + /** Cached ClassLoaders in active state */ + private static final Map uniqueKeyToLoaderActive = new HashMap(); + /** Cached ClassLoaders which removal is pending, i.e. {@link #PENDING_REMOVAL_TO} */ + private static final Map uniqueKeyToLoaderPending = new HashMap(); + /** Period in milliseconds to wait until removing pending ClassLoaders, i.e. {@value} ms */ + private static final long PENDING_REMOVAL_TO = 60*1000; /** map from JNLPFile unique key to lock, the lock is needed to enforce correct * initialization of applets that share a unique key*/ - private static Map uniqueKeyToLock = new HashMap(); + private static final Map uniqueKeyToLock = new HashMap(); /** Provides a search path & temporary storage for native code */ private final NativeLibraryStorage nativeLibraryStorage; @@ -435,6 +441,21 @@ public class JNLPClassLoader extends URLClassLoader { final JNLPFile f = getJNLPFile(); return "JNLPClassLoader@"+hashCode()+"[refCnt "+useCount+", file "+f.getFileLocation()+", code "+f.getCodeBase()+"]"; } + + private static JNLPClassLoader getCached(final String uniqueKey) { + synchronized(uniqueKeyMapLock) { + JNLPClassLoader res = uniqueKeyToLoaderActive.get(uniqueKey); + if( null == res ) { + res = uniqueKeyToLoaderPending.remove(uniqueKey); + if( null != res ) { + uniqueKeyToLoaderActive.put(uniqueKey, res); + OutputController.getLogger().log("JNLPClassLoader.Cache.reactivated: key "+uniqueKey +" -> "+res); + } + } + return res; + } + } + /** * Returns a JNLP classloader for the specified JNLP file. * @@ -449,7 +470,7 @@ public class JNLPClassLoader extends URLClassLoader { final OutputController out = OutputController.getLogger(); synchronized ( getUniqueKeyLock(uniqueKey) ) { - baseLoader = uniqueKeyToLoader.get(uniqueKey); + baseLoader = getCached(uniqueKey); out.log("JNLPClassLoader.Cache: file isApp "+file.isApplication()+", file "+file.getFileLocation()+", code "+file.getCodeBase()); out.log("JNLPClassLoader.Cache: key "+uniqueKey +" -> "+baseLoader); final int mode; @@ -513,7 +534,7 @@ public class JNLPClassLoader extends URLClassLoader { JNLPClassLoader loader; synchronized ( getUniqueKeyLock(uniqueKey) ) { - loader = uniqueKeyToLoader.get(uniqueKey); + loader = getCached(uniqueKey); if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation())) { JNLPFile jnlpFile = new JNLPFile(location, uniqueKey, version, settings, policy); @@ -2230,7 +2251,28 @@ public class JNLPClassLoader extends URLClassLoader { useCount--; if (useCount <= 0) { - uniqueKeyToLoader.remove(uniqueKey); + synchronized(uniqueKeyMapLock) { + final JNLPClassLoader pending = uniqueKeyToLoaderActive.remove(uniqueKey); + uniqueKeyToLoaderPending.put(uniqueKey, pending); + OutputController.getLogger().log("JNLPClassLoader.Cache.removed: Pending "+pending); + final Thread removePendingThread = new Thread("Pending removal of "+pending.toString()) { + @Override + public void run() { + try { + Thread.sleep(PENDING_REMOVAL_TO); + } catch (InterruptedException e) { } + final JNLPClassLoader removed = uniqueKeyToLoaderPending.remove(uniqueKey); + if( null != removed ) { + OutputController.getLogger().log("JNLPClassLoader.Cache.removed: Terminated "+removed); + } + } }; + removePendingThread.setDaemon(true); + removePendingThread.start(); + /** FIXME: When to remove the uniqueKeyToLock ? + synchronized (uniqueKeyToLock) { + uniqueKeyToLock.remove(uniqueKey); + } */ + } } } } -- cgit v1.2.3