Java Swing UI线程何时创建?
在运行Swing程序的过程中 UI线程(事件调度线程,EDT)首次生成? 想必任何给定的JVM都可以做它想做的任何事情 (例如,始终在启动时生成EDT,无论 或者从未使用过),但在 EDT通常是创建的吗 它是在SwingUtilities.invokeLater()时创建的吗 第一个叫什么?当JPanel第一次被实例化时? 如果事件泵与创建事件泵分开启动Java Swing UI线程何时创建?,java,swing,event-dispatch-thread,Java,Swing,Event Dispatch Thread,在运行Swing程序的过程中 UI线程(事件调度线程,EDT)首次生成? 想必任何给定的JVM都可以做它想做的任何事情 (例如,始终在启动时生成EDT,无论 或者从未使用过),但在 EDT通常是创建的吗 它是在SwingUtilities.invokeLater()时创建的吗 第一个叫什么?当JPanel第一次被实例化时? 如果事件泵与创建事件泵分开启动 EDT,通常在什么时候发生?查看代码后,它似乎是“延迟初始化”的,这意味着如果尚未初始化,它将在需要时立即初始化。在这种情况下,无论何时将任何
EDT,通常在什么时候发生?查看代码后,它似乎是“延迟初始化”的,这意味着如果尚未初始化,它将在需要时立即初始化。在这种情况下,无论何时将任何事件发布到其队列中
以下是完整的故事:
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;
}
dispatchThread
是使用包私有方法initDispatchThread()
初始化的:
Toolkit是一个抽象类。我们不是实例化此类的对象,而是创建Toolkit子类的实例:SunToolkit
。我们需要知道这一点,才能看到队列是在哪里创建的
一旦有了工具箱,我们就可以使用Toolkit\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\u QUEUE\u 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组件)调用它时创建)如果您对此有任何疑问,请告诉我,以便进行非常透彻的解释,但是OP应该基于,而不关心(相当多的)实现细节。文斯,谢谢您的回答。一个次要的后续问题:这是java规范/公共接口/文档所要求的明确答案,还是“仅仅”在当前版本的swing(一个合理的实现)中,它的实现方式可能会发生变化,但在新版本中可能会发生变化?@cal规范不需要它,因为它是一个库,而不是一个实际的语言规范(如for循环、if语句等)。至于在新版本中进行更改,这是可能的,但我怀疑是否会有任何重大更改,因为JavaFX旨在取代Swing。虽然我看到了一些小的调整,但主要结构还是保持不变,正如垃圾神提到的,这些都是你不应该担心的事情;您应该担心API是否会更改,不是“每个EventQueue都有自己的EDT”的实现有点准确,而是在实践中,多个EventQueue之间共享相同的EDT-请参阅push()和pop()对dispatchThread字段的处理。@VinceEmigh和Upvots,对于那些在答案中投入精力的人;-)
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;
}
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();
}