Java Swing UI线程何时创建?

Java Swing UI线程何时创建?,java,swing,event-dispatch-thread,Java,Swing,Event Dispatch Thread,在运行Swing程序的过程中 UI线程(事件调度线程,EDT)首次生成? 想必任何给定的JVM都可以做它想做的任何事情 (例如,始终在启动时生成EDT,无论 或者从未使用过),但在 EDT通常是创建的吗 它是在SwingUtilities.invokeLater()时创建的吗 第一个叫什么?当JPanel第一次被实例化时? 如果事件泵与创建事件泵分开启动 EDT,通常在什么时候发生?查看代码后,它似乎是“延迟初始化”的,这意味着如果尚未初始化,它将在需要时立即初始化。在这种情况下,无论何时将任何

在运行Swing程序的过程中 UI线程(事件调度线程,EDT)首次生成? 想必任何给定的JVM都可以做它想做的任何事情 (例如,始终在启动时生成EDT,无论 或者从未使用过),但在 EDT通常是创建的吗

它是在SwingUtilities.invokeLater()时创建的吗 第一个叫什么?当JPanel第一次被实例化时? 如果事件泵与创建事件泵分开启动
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();
}
因此,快速概述一下:

  • EDT位于EventQueue中
  • EventQueue位于Toolkit中
  • 队列是在创建工具箱时创建的
  • 工具箱可以手动创建(通过调用
    toolkit.getDefaultToolkit()
    ,也可以在程序的另一部分(例如将数据发布到队列的Swing组件)调用它时创建)
  • 只要将事件发布到队列中,就会创建EDT(并且EDT尚未运行)

  • 如果您对此有任何疑问,请告诉我,以便进行非常透彻的解释,但是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();
    }