diff options
author | Sven Gothel <[email protected]> | 2014-01-31 07:36:16 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-01-31 07:36:16 +0100 |
commit | f5a0517ac704b36e3d94aa3d5547ddf95889ab95 (patch) | |
tree | 5f860bdea0ae154d2a99124882769121b1d4117f | |
parent | d7c49c05158f34bb8fd62bbc7374131711cc92b8 (diff) |
JNLPClassLoader: Introduce pending removal of cached CLs (1 min) to enhance performance for single applet reload.
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java | 52 |
1 files 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<String, JNLPClassLoader> uniqueKeyToLoader = new ConcurrentHashMap<String, JNLPClassLoader>(); + private static final Object uniqueKeyMapLock = new Object(); + /** Cached ClassLoaders in active state */ + private static final Map<String, JNLPClassLoader> uniqueKeyToLoaderActive = new HashMap<String, JNLPClassLoader>(); + /** Cached ClassLoaders which removal is pending, i.e. {@link #PENDING_REMOVAL_TO} */ + private static final Map<String, JNLPClassLoader> uniqueKeyToLoaderPending = new HashMap<String, JNLPClassLoader>(); + /** 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<String, ReentrantLock> uniqueKeyToLock = new HashMap<String, ReentrantLock>(); + private static final Map<String, ReentrantLock> uniqueKeyToLock = new HashMap<String, ReentrantLock>(); /** 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); + } */ + } } } } |