Просмотрев код, кажется, что он «лениво инициализирован», что означает его инициализацию, как только это необходимо, если оно еще не инициализировано. В этом случае всякий раз, когда какое-либо событие отправляется в очередь.
Вот полная история:
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()
:
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: SunToolkit
.Нам нужно знать это, чтобы увидеть, где создается очередь.
Как только у нас есть Инструментарий, мы можем получить доступ к его EventQueue, используя 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_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();
}
Так краткий обзор:
- The EDT находится в EventQueue
- EventQueue находится в Toolkit
- Очередь создается при создании инструментария
- Инструментарий создается либо вручную (путем вызова
Toolkit.getDefaultToolkit()
, либо когда другая часть программы (например, Swing Компонент размещение данных в очереди) звонки на нем)
- EDT создается любое событие публикуется в очереди (а разве EDT уже запущен)
Позвольте мне знать, если у вас есть какие-либо вопросы по этому поводу
+1 для очень тщательной экспликации, но OP должен опираться на [поток отправки сообщений] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html) и не заботиться о (значительная) информация о реализации. – trashgod
Винс, спасибо за хороший ответ. Небольшие последующие вопросы: Является ли это окончательным ответом в том смысле, что вышеуказанное требуется спецификацией java/публичным интерфейсом/документацией, или это «просто», как это происходит в текущей версии swing - - одна разумная реализация - но может измениться в новой версии? – cal
@cal. В спецификации не обязательно указывать, как это библиотека, а не фактическая спецификация языка * (например, для циклов, если инструкции и т. Д.). Что касается изменения в новой версии, это возможно, но я сомневаюсь, что любые огромные изменения будут сделаны, поскольку JavaFX должен был заменить Swing. Хотя я видел незначительные корректировки, основная структура осталась прежней, и, как упоминалось выше, это вещи, о которых вы не должны беспокоиться; вы должны беспокоиться о том, изменится ли API, а не в реализации. –