在运行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;
}

使用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) 调用)中
  • 在package-private方法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子类的一个实例: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();
    }
    

    快速概述:
  • EDT位于EventQueue
  • EventQueue位于工具包
  • 创建工具包
  • 时创建队列
  • 该工具包是手动创建的(通过调用Toolkit.getDefaultToolkit(),或者每当程序的另一部分(例如将数据发布到队列中的Swing组件)调用时)
  • 只要将事件发布到队列(并且EDT尚未运行),就会创建EDT。

    如果您对此有任何疑问,请告诉我

  • 10-06 05:31