6636370: minor corrections and simplification of code in AppContext

MainAppContext, isDisposed, and numAppContexts has beem made volatile.  mostRecentThreadAppContext has been rewritten using ThreadLocal.

Reviewed-by: art
This commit is contained in:
Oleg Sukhodolsky 2008-03-13 16:54:51 +03:00
parent 794142ee36
commit 9c0e7108a3

View File

@ -154,7 +154,7 @@ public final class AppContext {
/* The main "system" AppContext, used by everything not otherwise /* The main "system" AppContext, used by everything not otherwise
contained in another AppContext. contained in another AppContext.
*/ */
private static AppContext mainAppContext = null; private static volatile AppContext mainAppContext = null;
/* /*
* The hash map associated with this AppContext. A private delegate * The hash map associated with this AppContext. A private delegate
@ -179,31 +179,30 @@ public final class AppContext {
public static final String DISPOSED_PROPERTY_NAME = "disposed"; public static final String DISPOSED_PROPERTY_NAME = "disposed";
public static final String GUI_DISPOSED = "guidisposed"; public static final String GUI_DISPOSED = "guidisposed";
private boolean isDisposed = false; // true if AppContext is disposed private volatile boolean isDisposed = false; // true if AppContext is disposed
public boolean isDisposed() { public boolean isDisposed() {
return isDisposed; return isDisposed;
} }
static { static {
// On the main Thread, we get the ThreadGroup, make a corresponding // On the main Thread, we get the ThreadGroup, make a corresponding
// AppContext, and instantiate the Java EventQueue. This way, legacy // AppContext, and instantiate the Java EventQueue. This way, legacy
// code is unaffected by the move to multiple AppContext ability. // code is unaffected by the move to multiple AppContext ability.
AccessController.doPrivileged(new PrivilegedAction() { AccessController.doPrivileged(new PrivilegedAction() {
public Object run() { public Object run() {
ThreadGroup currentThreadGroup = ThreadGroup currentThreadGroup =
Thread.currentThread().getThreadGroup(); Thread.currentThread().getThreadGroup();
ThreadGroup parentThreadGroup = currentThreadGroup.getParent(); ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
while (parentThreadGroup != null) { while (parentThreadGroup != null) {
// Find the root ThreadGroup to construct our main AppContext // Find the root ThreadGroup to construct our main AppContext
currentThreadGroup = parentThreadGroup; currentThreadGroup = parentThreadGroup;
parentThreadGroup = currentThreadGroup.getParent(); parentThreadGroup = currentThreadGroup.getParent();
}
mainAppContext = new AppContext(currentThreadGroup);
numAppContexts = 1;
return mainAppContext;
} }
mainAppContext = new AppContext(currentThreadGroup);
numAppContexts = 1;
return mainAppContext;
}
}); });
} }
@ -214,7 +213,7 @@ public final class AppContext {
* number is 1. If so, it returns the sole AppContext without * number is 1. If so, it returns the sole AppContext without
* checking Thread.currentThread(). * checking Thread.currentThread().
*/ */
private static int numAppContexts; private static volatile int numAppContexts;
/* /*
* The context ClassLoader that was used to create this AppContext. * The context ClassLoader that was used to create this AppContext.
@ -241,14 +240,15 @@ public final class AppContext {
threadGroup2appContext.put(threadGroup, this); threadGroup2appContext.put(threadGroup, this);
this.contextClassLoader = this.contextClassLoader =
(ClassLoader) AccessController.doPrivileged(new PrivilegedAction() { AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
public Object run() { public ClassLoader run() {
return Thread.currentThread().getContextClassLoader(); return Thread.currentThread().getContextClassLoader();
} }
}); });
} }
private static MostRecentThreadAppContext mostRecentThreadAppContext = null; private static final ThreadLocal<AppContext> threadAppContext =
new ThreadLocal<AppContext>();
/** /**
* Returns the appropriate AppContext for the caller, * Returns the appropriate AppContext for the caller,
@ -265,59 +265,46 @@ public final class AppContext {
if (numAppContexts == 1) // If there's only one system-wide, if (numAppContexts == 1) // If there's only one system-wide,
return mainAppContext; // return the main system AppContext. return mainAppContext; // return the main system AppContext.
final Thread currentThread = Thread.currentThread(); AppContext appContext = threadAppContext.get();
AppContext appContext = null; if (null == appContext) {
appContext = AccessController.doPrivileged(new PrivilegedAction<AppContext>()
{
public AppContext run() {
// Get the current ThreadGroup, and look for it and its
// parents in the hash from ThreadGroup to AppContext --
// it should be found, because we use createNewContext()
// when new AppContext objects are created.
ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
ThreadGroup threadGroup = currentThreadGroup;
AppContext context = threadGroup2appContext.get(threadGroup);
while (context == null) {
threadGroup = threadGroup.getParent();
if (threadGroup == null) {
// If we get here, we're running under a ThreadGroup that
// has no AppContext associated with it. This should never
// happen, because createNewContext() should be used by the
// toolkit to create the ThreadGroup that everything runs
// under.
throw new RuntimeException("Invalid ThreadGroup");
}
context = threadGroup2appContext.get(threadGroup);
}
// In case we did anything in the above while loop, we add
// all the intermediate ThreadGroups to threadGroup2appContext
// so we won't spin again.
for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg.getParent()) {
threadGroup2appContext.put(tg, context);
}
// Now we're done, so we cache the latest key/value pair.
// (we do this before checking with any AWTSecurityManager, so if
// this Thread equates with the main AppContext in the cache, it
// still will)
threadAppContext.set(context);
// Note: this most recent Thread/AppContext caching is thread-hot. return context;
// A simple test using SwingSet found that 96.8% of lookups
// were matched using the most recent Thread/AppContext. By
// instantiating a simple MostRecentThreadAppContext object on
// cache misses, the cache hits can be processed without
// synchronization.
MostRecentThreadAppContext recent = mostRecentThreadAppContext;
if ((recent != null) && (recent.thread == currentThread)) {
appContext = recent.appContext; // Cache hit
} else {
appContext = (AppContext)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
// Get the current ThreadGroup, and look for it and its
// parents in the hash from ThreadGroup to AppContext --
// it should be found, because we use createNewContext()
// when new AppContext objects are created.
ThreadGroup currentThreadGroup = currentThread.getThreadGroup();
ThreadGroup threadGroup = currentThreadGroup;
AppContext context = threadGroup2appContext.get(threadGroup);
while (context == null) {
threadGroup = threadGroup.getParent();
if (threadGroup == null) {
// If we get here, we're running under a ThreadGroup that
// has no AppContext associated with it. This should never
// happen, because createNewContext() should be used by the
// toolkit to create the ThreadGroup that everything runs
// under.
throw new RuntimeException("Invalid ThreadGroup");
} }
context = threadGroup2appContext.get(threadGroup); });
}
// In case we did anything in the above while loop, we add
// all the intermediate ThreadGroups to threadGroup2appContext
// so we won't spin again.
for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg.getParent()) {
threadGroup2appContext.put(tg, context);
}
// Now we're done, so we cache the latest key/value pair.
// (we do this before checking with any AWTSecurityManager, so if
// this Thread equates with the main AppContext in the cache, it
// still will)
mostRecentThreadAppContext =
new MostRecentThreadAppContext(currentThread, context);
return context;
}
});
} }
if (appContext == mainAppContext) { if (appContext == mainAppContext) {
@ -326,9 +313,9 @@ public final class AppContext {
// allow it to choose the AppContext to return. // allow it to choose the AppContext to return.
SecurityManager securityManager = System.getSecurityManager(); SecurityManager securityManager = System.getSecurityManager();
if ((securityManager != null) && if ((securityManager != null) &&
(securityManager instanceof AWTSecurityManager)) { (securityManager instanceof AWTSecurityManager))
AWTSecurityManager awtSecMgr = {
(AWTSecurityManager)securityManager; AWTSecurityManager awtSecMgr = (AWTSecurityManager)securityManager;
AppContext secAppContext = awtSecMgr.getAppContext(); AppContext secAppContext = awtSecMgr.getAppContext();
if (secAppContext != null) { if (secAppContext != null) {
appContext = secAppContext; // Return what we're told appContext = secAppContext; // Return what we're told
@ -455,7 +442,7 @@ public final class AppContext {
// Threads in the ThreadGroup to exit. // Threads in the ThreadGroup to exit.
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
long endTime = startTime + (long)THREAD_INTERRUPT_TIMEOUT; long endTime = startTime + THREAD_INTERRUPT_TIMEOUT;
while ((this.threadGroup.activeCount() > 0) && while ((this.threadGroup.activeCount() > 0) &&
(System.currentTimeMillis() < endTime)) { (System.currentTimeMillis() < endTime)) {
try { try {
@ -470,7 +457,7 @@ public final class AppContext {
// Threads in the ThreadGroup to die. // Threads in the ThreadGroup to die.
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
endTime = startTime + (long)THREAD_INTERRUPT_TIMEOUT; endTime = startTime + THREAD_INTERRUPT_TIMEOUT;
while ((this.threadGroup.activeCount() > 0) && while ((this.threadGroup.activeCount() > 0) &&
(System.currentTimeMillis() < endTime)) { (System.currentTimeMillis() < endTime)) {
try { try {
@ -489,10 +476,7 @@ public final class AppContext {
} }
threadGroup2appContext.remove(this.threadGroup); threadGroup2appContext.remove(this.threadGroup);
MostRecentThreadAppContext recent = mostRecentThreadAppContext; threadAppContext.set(null);
if ((recent != null) && (recent.appContext == this))
mostRecentThreadAppContext = null;
// If the "most recent" points to this, clear it for GC
// Finally, we destroy the ThreadGroup entirely. // Finally, we destroy the ThreadGroup entirely.
try { try {
@ -675,6 +659,7 @@ public final class AppContext {
* Returns a string representation of this AppContext. * Returns a string representation of this AppContext.
* @since 1.2 * @since 1.2
*/ */
@Override
public String toString() { public String toString() {
return getClass().getName() + "[threadGroup=" + threadGroup.getName() + "]"; return getClass().getName() + "[threadGroup=" + threadGroup.getName() + "]";
} }
@ -780,15 +765,6 @@ public final class AppContext {
} }
} }
final class MostRecentThreadAppContext {
final Thread thread;
final AppContext appContext;
MostRecentThreadAppContext(Thread key, AppContext value) {
thread = key;
appContext = value;
}
}
final class MostRecentKeyValue { final class MostRecentKeyValue {
Object key; Object key;
Object value; Object value;