在运行Swing程序的过程中,是 UI线程(事件调度线程,EDT)首先产生? 据推测,任何给定的JVM都可以做任何想做的事情 (例如,无论是在启动时总是产生EDT 或不是它曾经使用过),但作为一个实际问题 EDT通常是创建的吗?
是否在SwingUtilities.invokeLater()时创建 是第一次打电话?首次实例化JPanel时? 如果事件泵与创建分开启动 美国东部时间,这通常会发生什么时候?
答案 0 :(得分:9)
在查看代码后,似乎它已经懒得初始化",这意味着如果尚未初始化,则会在需要时立即初始化。在这种情况下,只要有任何事件发布到它的队列。
以下是完整的故事:
EventDispatchThread
封装在EventQueue
中。每个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;
}
使用package-private方法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)
调用)EventQueue#createSecondaryLoop(Conditional, EventFilter, long)
。在调用initDispatchThread()
之前,会检查dispatchThread
,确保它尚未初始化。有几种方法可以在JDK中查看类的完整源代码(最简单的是附加源代码);如果您真的感兴趣,请查看这些方法。
所以现在我们知道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#getSystemEventQueue()
访问它的EventQueue。这个望远镜采用受保护的抽象方法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();
}
快速概述:
Toolkit.getDefaultToolkit()
,或者每当程序的其他部分(例如向队列发布数据的Swing组件)调用它时)如果您对此有任何疑问,请与我们联系。