2009-09-15 11 views
6

W ciągu ostatnich kilku lat głównie rozwijałem UI w Eclipse, co jest bardzo konserwatywne pod względem dostępu do wątku: każda próba zmiany właściwości widżetu interfejsu użytkownika (np. Koloru, tekstu) spoza wątków interfejsu użytkownika wyjątek.Co się stanie, gdy naruszona zostanie polityka Swinga dotycząca gwintowania?

Teraz szukam istniejącego programu w Swing, który ma okno z dużą liczbą niestandardowych widgetów. Istnieją osobne wątki, które uruchamiają funkcję mutacji dla każdego z tych widgetów, a funkcja mutacji odczytuje wartość niektórych rzeczy (np. Kolory i wartości etykiet) i zapisuje niektóre (np. Zmienia kolory tła). Zauważ, że nie ma w tym przypadku niestandardowego malowania lub czegoś podobnego, tylko kilka zmian w podrzędnych elementach widżetów, które zawierają głównie JLabelki.

Obecnie trwa to od oddzielnego wątku, a nie od wątku zdarzenia Swing. Ten wątek obejmuje wszystkie 400 widgetów i wywołuje mutator na każdym z nich. Wydaje się, że aktualizacje działają poprawnie, ale GUI nie reaguje na dane wprowadzone przez użytkownika.

Jeśli przyjmiemy całą rzecz, która działa przez około 0,4 milisekundy spoza wątku Swing i zawija każde wywołanie do mutatora w wywołaniu WhenLock lub invokeAndWait, interfejs jest o wiele bardziej responsywny.

Co Próbuję zrozumieć to:

1) Czy czasami uzasadnione, aby wszystkie te połączenia spoza wątku Swing?

2) Jaki jest wpływ na wątek Swing i dlaczego interfejs jest mniej responsywny, gdy nazywam go z zewnątrz?

Odpowiedz

3

Od "Nic" do przerywanych problemów do "Wszystko się psuje, odciągnij wszystkich do pracy przy GUI!"

Głównym (najbardziej oczywistym) efektem wizualnym jest to, że jeśli przytrzymasz wątek GUI (jak ktoś naciśnie przycisk i wykonasz uśpienie (5000) lub coś takiego), twój GUI nie odświeży się. Nie może, ponieważ trzymasz się jedynego wątku, który może ci ominąć! To sprawia, że ​​ludzie myślą, że Java jest naprawdę powolna. To nie jest złe, ale programowanie jest łatwe, ponieważ wiele osób, które nie zawracają sobie głowy badaniem takich praktyk, stworzyło produkty do wysyłki.

Kolejnym największym problemem jest to, że podczas rysowania ekranu w innym wątku (takim jak ten przekazywany do głównego), może on mieć dziwne zachowanie. Swing jest już zbyt wybredny, jeśli chodzi o renderowanie ramek - wyłuskaj wątek jako zmienną!

Wreszcie, rzadko (lub często, jeśli wywołujesz element swing w ciasnej pętli na niewłaściwym wątku), możesz uzyskać kolizje gwintu. Jeśli tak się stanie, wyjątek może zostać odrzucony (lub nie) i prawdopodobnie coś się nie powiedzie, ale może nie być oczywiste.

1

Podstawowym problemem jest to, że obiekty nie podlegające gwintowaniu są wykonywane w sposób wielowątkowy. Nawet coś tak prostego jak czytanie HashMap może zostać przechwycone w nieskończonej pętli. Ponieważ AWT używa blokad (źle), możesz również skończyć z zakleszczeniami. Prawdopodobnie jednak uszło ci to na sucho, chociaż może się okazać, że zaktualizowana wersja Java nagle powoduje problemy na niektórych komputerach klienta.

(BTW. To wydarzenie Wysłanie AWT wątku, a nie Swing'S)

1

dla (1) jako reguła kciuka, który aktualizuje niczego pikseli na ekranie musi być wywoływana z Event Dispatching Thread (EDT). Gdy niektóre maszyny JVM mogą akceptować aktualizacje spoza EDT, nie należy polegać na tym działaniu, niektóre maszyny i inny wygląd i odczucia nie będą działać w sposób dopuszczalny. Zachowanie jest nieokreślone - a to może tłumaczyć brak wyczulenia.

3

1) Czy czasami uprawnione jest wykonywanie wszystkich tych połączeń poza wątkiem Swing?

Istnieje kilka wyjątków (ustawienie wartości tekstowej pola tekstowego, na przykład, automatyczne pośredniczenie przez serwer proxy EDT) - ale są sytuacje, w których lepiej jest to zrobić w przypadku sytuacji no. Jeśli wykonujesz wiele aktualizacji, możesz wykonać je wszystkie w jednym wywołaniu EDT (pojedyncze wywołanie invokeLater()) zamiast pojedynczych wywołań - ale nawet taki rodzaj grupowania bardzo rzadko pomaga. Długie i krótkie: Wykonuj operacje na elementach Swing z EDT. Obejmuje to odczytywanie i zapisywanie.

2) Jaki jest wpływ na wątek Swing i dlaczego interfejs jest mniej responsywny, gdy nazywam go z zewnątrz?

Cóż, EDT jest odpowiedzialny za aktualizację GUI. Jeśli dzwonisz z zewnątrz, nie jest "mniej responsywny" - to fakt, że rzeczywiste połączenia systemowe o niskim poziomie, które aktualizują interfejs użytkownika, nie występują (w ogóle). To, co prawdopodobnie dzieje się w Twojej aplikacji, to fakt, że oryginalni programiści mają szczęście i zmieniają stan w komponencie swing bez tworzenia naprawdę nieprzyjemnych warunków wyścigowych. Następnie inne zdarzenie powoduje odmalowanie w EDT, co powoduje aktualizację komponentu. Może to wydawać się "brakiem reakcji" - ale to, co naprawdę się dzieje, to "brak odświeżania ekranu".

EDT to zwykły wątek, ale jest nieco wyjątkowy, ponieważ działa w ciasnej pętli, która przetwarza sygnały powiązane z GUI (na przykład polecenia rysowania). Semanteki wysyłania tego typu poleceń do EDT naprawdę różnią się od tego, co zwykle uważamy za wątki Java (polega to na przesyłaniu operacji do pompy komunikatów).

Długie i krótkie - wszystkie te Javadoki, które mówią "tylko wchodzić w interakcje z obiektami Swing na EDT", są napisane bez powodu. Nie zadzieraj z tym. Jeśli chcesz wykonać przetwarzanie w tle, dobrze - ale jesteś odpowiedzialny za pośredniczenie w interakcji z komponentami J * z powrotem na EDT (najczęściej za pomocą metody invokeLater()).

2
  1. Naprawdę nie ma wyjątków. Kevin jest częściowo poprawny - JTextComponent.setText() jest reklamowany jako bezpieczny dla wątków. Jednak patrząc na kod 1.6, zapewnia synchronizację na obiekcie dokumentu i nie korzysta z EDT. Jest to w porządku, chyba że inny element swingujący (lub coś, co kontroluje komponenty swing) słucha obiektu dokumentu. Oszczędź sobie kłopotu z martwieniem się o to i po prostu zawsze używaj EDT - tak jak mówi Kevin, naprawdę nie ma sytuacji (których jestem świadomy), aby zrobić inaczej.

  2. Trudno powiedzieć bez wkopywania się w kod; zachowanie jest niezdefiniowane. Jeśli twoje zadania w tle były długie (> kilka sekund), zobaczysz odwrotny efekt - użycie EDT spowoduje brak reakcji interfejsu użytkownika podczas wykonywania zadań.

Na szczęście brzmi to jak robienie tego we właściwy sposób działa najlepiej dla Ciebie. :)

Sun mawiał było ok do korzystania z innych tematów z elementów, które nie zostały zrealizowane, ale później odwołał:

Related stackoverflow question

Check out samouczek UI Sun na huśtawce i współbieżności (I 'd wysłać link, ale to jest moja pierwsza odpowiedź na stackoverflow0.

Powiązane problemy