查看代码后,它似乎是“延迟初始化”的,这意味着它会在需要时立即初始化(如果尚未初始化)。在这种情况下,每当任何事件被发布到其队列中时。
完整的故事如下:
The EventDispatchThread
被封装在EventQueue
. Each EventQueue
有自己的 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
使用包私有方法初始化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();
}
}
检查对该方法的引用后,有 3 个地方调用了该方法:
- 在私有方法中
EventQueue#wakeup(boolean)
- 在私有方法中
EventQueue#postEventPrivate(AWTEvent)
(由公共方法调用EventQueue#postEvent(AWTEvent) http://docs.oracle.com/javase/8/docs/api/java/awt/EventQueue.html#postEvent-java.awt.AWTEvent-)
- 在包私有方法中
EventQueue#createSecondaryLoop(Conditional, EventFilter, long)
.
Before initDispatchThread()
叫做,dispatchThread
检查以确保它尚未初始化。有几种方法可以查看 JDK 中类的完整源代码(最简单的是附加源代码);如果您是,请研究这些方法REALLY感兴趣的。
所以现在我们知道了EventQueue
包含线程,并且只要实际需要(发布事件),就会创建线程。是时候讨论这个队列所在的位置以及事物如何与其通信了。
如果你检查代码EventQueue#invokeLater(Runnable)
(这被称为SwingUtilities
对应),你会看到它调用Toolkit.getEventQueue().postEvent(...)
。这告诉我们队列位于Toolkit
.
在 - 的里面Toolkit
类,我们可以看到它在我们每次调用它时都已创建(如果还没有)。它使用反射来创建对象:
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 是一个抽象类。我们不是实例化此类的对象,而是创建 Toolkit 子类的实例:SunToolkit
。我们需要知道这一点才能查看队列是在哪里创建的。
一旦我们有了 Toolkit,我们就可以使用它来访问它的 EventQueueToolkit#getSystemEventQueue()
。这涉及受保护的抽象方法getSystemEventQueueImpl()
。我们必须检查子类以查看此方法的实现。在 SunToolkit 类中,我们有:
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)
队列即将到来appContext
工具包的。现在我们要做的就是找到队列添加到应用程序上下文的位置:
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();
}
快速概述一下:
- EDT 位于 EventQueue 内
- EventQueue 位于 Toolkit 内
- 创建工具包时会创建队列
- 该工具包可以手动创建(通过调用
Toolkit.getDefaultToolkit()
,或者每当程序的另一部分(例如将数据发送到队列的 Swing 组件)调用它时)
- 每当事件发布到队列时都会创建 EDT(并且 EDT 尚未运行)
如果您对此有任何疑问,请告诉我