Jeśli narzędzia pobierające modele Swing nie są bezpieczne dla wątków, jak sobie z nimi radzisz?
Powszechnie wiadomo, że aktualizacja GUI Swing musi być przeprowadzana wyłącznie w EDT. Mniej reklamuje się toczytanie rzeczy z GUI muszą / powinny być również wykonane w EDT. Na przykład, weźmyButtonModel's isSelected () metoda, która informuje (na przykład) o stanie ToggleButton („w dół” lub „w górę”).
W każdym przykładzie, który widziałem,isSelected()
jest swobodnie odpytywany z głównego lub dowolnego wątku. Ale kiedy patrzę na implementację DefaultButtonModel, nie jest zsynchronizowana, a wartość nie jest zmienna. Więc, ściśle mówiąc,isSelected()
może zwrócić śmieci, jeśli jest odczytywane z dowolnego innego wątku niż ten, z którego jest ustawiony (czyli EDT, gdy użytkownik naciska przycisk). A może się mylę?
Początkowo myślałem o tym, gdy byłem zszokowany punktem # 66 w Efektywnej Javie Blocha, w tym przykładzie:
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;
}
}
Wbrew pozorom ten program nigdy się nie kończy, przynajmniej na niektórych komputerach. AktualizowaniestopRequested
flaga z głównego wątku jest niewidoczna dla wątku w tle. Sytuację można naprawić za pomocą zsynchronizowanych pobierających i ustawiających lub ustawiając flagęvolatile
.
Więc:
Czy sprawdzanie stanu modelu Swing poza EDT (ściśle mówiąc) jest błędne?Jeśli nie, jak to się stało?Jeśli tak, jak sobie z tym poradzisz? Na szczęście, lub przez jakieś sprytne obejście? InvokeAndWait?