问题
When, in the process of running a Swing program, is the UI thread (event-dispatch thread, EDT) first spawned? Presumably any given JVM could do whatever it wants (for example, always spawning the EDT at start-up, whether or not it's ever used), but as a practical matter when is the EDT typically created?
Does it get created when SwingUtilities.invokeLater() is first called? When a JPanel is first instantiated? And if the event pump is started separately from creating the EDT, when does that typically happen?
回答1:
After looking through the code, it seems as if it's "lazily initialized", meaning its initialized as soon as its needed, if not already initialized. In this case, whenever any event is posted to it's queue.
Here's the full story:
The EventDispatchThread
is encapsulated within EventQueue
. Each EventQueue
has its own EDT:
/**
* Just a summary of the class
*/
public class EventQueue {
private static final int ULTIMATE_PRIORITY = 3;
private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
private Queue[] queues = new Queue[NUM_PRIORITIES];
private EventQueue nextQueue;
private EventQueue previousQueue;
private EventDispatchThread dispatchThread;
}
The dispatchThread
is initialized using the package-private method initDispatchThread()
:
final void initDispatchThread() {
pushPopLock.lock();
try {
if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
dispatchThread = AccessController.doPrivileged(
new PrivilegedAction<EventDispatchThread>() {
public EventDispatchThread run() {
EventDispatchThread t =
new EventDispatchThread(threadGroup,
name,
EventQueue.this);
t.setContextClassLoader(classLoader);
t.setPriority(Thread.NORM_PRIORITY + 1);
t.setDaemon(false);
AWTAutoShutdown.getInstance().notifyThreadBusy(t);
return t;
}
}
);
dispatchThread.start();
}
} finally {
pushPopLock.unlock();
}
}
After checking for references to this method, there are a 3 places where this method is called:
- In the private method
EventQueue#wakeup(boolean)
- In the private method
EventQueue#postEventPrivate(AWTEvent)
(which is called by the public method EventQueue#postEvent(AWTEvent)) - In the package-private method
EventQueue#createSecondaryLoop(Conditional, EventFilter, long)
.
Before initDispatchThread()
is called, dispatchThread
is checked make sure it's not already initialized. There are a few ways you can view the entire source code for a class in the JDK (easiest being attaching source); look into these methods if you're REALLY interested.
So now we know EventQueue
contains the thread, and the thread is created whenever it's actually needed (an event gets posted). Time to talk about where this queue is located and how things communicate with it.
If you check the code of EventQueue#invokeLater(Runnable)
(which is called by it's SwingUtilities
counterpart), you'll see that it calls Toolkit.getEventQueue().postEvent(...)
. This tells us the queue is located in Toolkit
.
Inside the Toolkit
class, we can see that it's created (if not already) any time we call for it. It uses reflection to create the object:
public static synchronized Toolkit getDefaultToolkit() {
if (toolkit == null) {
try {
java.lang.Compiler.disable();
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
String nm = null;
Class<?> cls = null;
try {
nm = System.getProperty("awt.toolkit");
try {
cls = Class.forName(nm);
} catch (ClassNotFoundException e) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
try {
cls = cl.loadClass(nm);
} catch (ClassNotFoundException ee) {
throw new AWTError("Toolkit not found: " + nm);
}
}
}
if (cls != null) {
toolkit = (Toolkit)cls.newInstance();
if (GraphicsEnvironment.isHeadless()) {
toolkit = new HeadlessToolkit(toolkit);
}
}
} catch (InstantiationException e) {
throw new AWTError("Could not instantiate Toolkit: " + nm);
} catch (IllegalAccessException e) {
throw new AWTError("Could not access Toolkit: " + nm);
}
return null;
}
});
loadAssistiveTechnologies();
} finally {
// Make sure to always re-enable the JIT.
java.lang.Compiler.enable();
}
}
return toolkit;
}
Toolkit is an abstract class. Instead of instantiating an object of this class, we are creating an instance of a subclass of Toolkit: SunToolkit
. We will need to know this to see where the queue is created.
Once we have the Toolkit, we can access it's EventQueue using Toolkit#getSystemEventQueue()
. This telescopes to the protected abstract method getSystemEventQueueImpl()
. We must check out the subclass to see the implementation for this method. In the SunToolkit class, we have:
protected EventQueue getSystemEventQueueImpl() {
return getSystemEventQueueImplPP();
}
// Package private implementation
static EventQueue getSystemEventQueueImplPP() {
return getSystemEventQueueImplPP(AppContext.getAppContext());
}
public static EventQueue getSystemEventQueueImplPP(AppContext appContext) {
EventQueue theEventQueue = (EventQueue) appContext.get(AppContext.EVENT_QUEUE_KEY);
return theEventQueue;
}
(EventQueue) appContext.get(AppContext.EVENT_QUEUE_KEY)
The queue is coming the appContext
of the toolkit. Now all we gotta do is find where the queue is added to the app context:
public SunToolkit() {
Runnable initEQ = new Runnable() {
public void run() {
EventQueue eventQueue;
String eqName = System.getProperty("AWT.EventQueueClass", "java.awt.EventQueue");
try {
eventQueue = (EventQueue) Class.forName(eqName).newInstance();
} catch (Exception e) {
e.printStackTrace();
System.err.println("Failed loading " + eqName + ": " + e);
eventQueue = new EventQueue();
}
AppContext appContext = AppContext.getAppContext();
appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue); //queue added here
PostEventQueue postEventQueue = new PostEventQueue(eventQueue);
appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue);
}
};
initEQ.run();
}
So a quick overview:
- The EDT is located within EventQueue
- The EventQueue is located within Toolkit
- The queue is created when you create the toolkit
- The toolkit is created either manually (by calling
Toolkit.getDefaultToolkit()
, or whenever another part of the program (such as a Swing component posting data to the queue) calls on it) - The EDT is created anytime an event is posted to the queue (and the EDT isnt already running)
Let me know if you have any questions about this
来源:https://stackoverflow.com/questions/26317766/when-is-the-swing-ui-thread-created