Различные спорадические проблемы в поддерживаемом мною приложении Swing, по-видимому, вызваны тем, что оно заменяет очередь событий AWT по умолчанию своей собственной версией, использующей Toolkit.getDefaultToolkit().getSystemEventQueue().push(new AEventQueue())
.См., Например, Потоки и взаимоблокировки в приложении Swing .Описанная там проблема была решена, но мои тесты (с использованием FEST Swing) теперь, как правило, зашли в тупик.
Я подозреваю, что лучшим решением было бы заменить очередь событий в начале инициализации приложения долюбые компоненты Swing созданы.Однако есть некоторые зависимости, которые делают это неловким, поэтому в настоящее время я пытаюсь найти безопасный способ «протолкнуть» новую очередь событий после инициализации, где это в настоящее время делается.
Два подхода, которые япробовали:
- выдвинуть новую очередь в EDT с помощью
SwingUtilities.invokeLater()
; - выдвинуть новую очередь в главном потоке после инициализации и после использования
invokeLater()
, чтобы избежать взаимоблокировкисо всем, что уже запущено в старом EDT.
Что я мог бы ожидать после прочтения https://stackoverflow.com/a/8965448/351885,, так это то, что первый подход может работать в Java 7, но что-то вроде второго может понадобиться вJava 1.6.Действительно, второй работает в Java 1.6, в то время как в Java 7 оба успешно завершаются, но работают очень медленно.Это может быть просто проблемой FEST, так как само приложение кажется довольно отзывчивым.
Так что я в значительной степени вынужден использовать второй подход, который по крайней мере работает в Java 1.6, но я хотел бы знать - еслиесть более безопасный способ реализовать это, так как кажется, что он может быть уязвим к состоянию гонки, если событие появляется в существующей очереди после invokeLater
, но до создания новой очереди;- если есть другой подход, я должен использовать вместо него.
Подробнее
Первое «решение» выглядит так:
initApplication();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new CustomEventQueue());
}
});
Когда я скомпилирован и запущен с использованием Java 1.6, я не понимаю, что он делает.Кажется, что поток ожидает блокировки, которую он уже удерживает:
"AWT-EventQueue-1" prio=10 tid=0x00007f9808001000 nid=0x6628 in Object.wait() [0x00007f986aa72000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007d9961cf0> (a atlantis.gui.AEventQueue)
at java.lang.Object.wait(Object.java:502)
at java.awt.EventQueue.getNextEvent(EventQueue.java:490)
- locked <0x00000007d9961cf0> (a atlantis.gui.AEventQueue)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:247)
Второе «решение» выглядит так:
initApplication();
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
logger.debug("Waiting for AWT event queue to be empty.");
}
});
} catch (InterruptedException e) {
logger.error("Interrupted while waiting for event queue.", e);
} catch (InvocationTargetException e) {
logger.error("Error while waiting for event queue.",e);
}
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new CustomEventQueue());
Как указано выше, похоже, что это работает нормальнов Java 1.6, но я не уверен, что это действительно безопасно.
Я не понял, что происходит при использовании Java 7, но основной поток, по-видимому, тратит много времени на сон метода org.fest.swing.timing.Pause.pause()
Вот почему я подозреваю, что это может быть проблема, связанная с FEST.