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:
parent
794142ee36
commit
9c0e7108a3
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user