Хорошо известно, что обновление GUI Swing должно выполняться исключительно в EDT. Меньше объявляется, что чтение материала из GUI должно/должно быть сделано в EDT. Например, пусть метод ButtonModel isSelected(), который сообщает (например) состояние ToggleButton ( "вниз" или "вверх" ).
В каждом примере, который я видел, isSelected()
запрашивается отдельно от основного или любого потока. Но когда я смотрю на реализацию DefaultButtonModel, он не синхронизируется, и значение не является изменчивым. Так что, строго говоря, isSelected()
может возвращать мусор, если он читает из любого другого потока, кроме того, из которого он установлен (который является EDT, когда пользователь нажимает кнопку). Или я ошибаюсь?
Я изначально думал об этом, когда был шокирован абзацем № 66 в Bloch Effective Java, этот пример:
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while(!stopRequested) i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
Вопреки тому, что кажется, эта программа никогда не заканчивается, по крайней мере на некоторых машинах. Обновление флага stopRequested
из основного потока невидимо для фонового потока. Ситуацию можно устранить с помощью синхронизированных геттеров и сеттеров или установить флаг volatile
.
Итак:
- Неправильно запрашивает состояние модели Swing вне EDT (строго говоря)?
- Если нет, то как?
- Если да, как вы справляетесь с этим? К счастью, или каким-то умным обходным решением? InvokeAndWait?