Nigdy nie używaj wait() w SwingWorkerze jeżeli nie potrafisz powtórzyć kodu źródłowego tej klasy wyrwany ze snu o trzeciej w nocy. :)
"Metoda wait() pozwala na zawieszenie wykonania zadania w oczekiwaniu na zmianę tych warunków wykonania, które pozostają poza jego kontrolą" (Bruce Eckel).
SwingWorker posługuje się synchronizacją, zatrzymywaniem i uruchamianiem swojego wątku, więc używając wait() tylko zaburzasz działanie tego kodu. Dlatego robiąc to musisz doskonale wiedzieć co robisz. Najwyraźniej tego nie wiesz i jedyne co może Ci pomóc w odpowiedzi na pytanie z komentarza, to analiza kodu źródłowego SwingWorkera i wszystkich powiązanych z nim klas (co może być trudne jeżeli natkniesz się na metody z pakietów Suna lub metody native).
Co do samego problemu. Zacząłeś prawidłowo, ale nie dokończyłeś i trochę namieszałeś.
Po pierwsze nie wolno Ci odpalać żadnej metody Swinga w metodzie doInBackground() - przede wszystkim sprawdzenia stanu okna. To jest inny wątek niż Swing. Nie ma więc też sensu robienie pętli opóźniających w tej metodzie - to jest Twoje miejsce wykonania pracy, którą zleciłeś, a nie oczekiwania na cokolwiek. SwingWorker dowie się o skończeniu tej pracy gdy ta procedura się zakończy.
Powinieneś zrobić tak:
W metodzie action blokujesz przycisk, tworzysz dialog (może być z paskiem postępu oraz przyciskiem anulowania) i odpalasz go. Następnie odpalasz przez execute klasę wywiedzioną ze SwingWorkera, w której metodzie doInBackground() robisz to co miało naprawdę robić Twoje wywołanie akcji. Jeżeli jest tam jakaś pętla, to wywołujesz w niej publish(), aby poinformować o postępie tego zadania. W metodzie process() (którą kieruje Swing) otrzymujesz wysłane przez publish() informacje o postępie dzięki którym możesz aktualizować na bieżąco pasek postępu czy jakiś zegar. Dialog informujący o konieczności czekania zamykasz w metodzie done() Twojego SwingWorkera (stąd konieczność final). Kiedy jest ona odpalana, to już ani razu nie odpali się process() bo praca w tle już się zakończyła, a on otrzymuje przecież dane z publish() wywoływanej w doInBackground().
NIE UŻYWASZ SLEEP, ANI TYM BARDZIEJ WAIT. Używając SwingWorkera możesz o nich zapomnieć bo są to procedury niższego poziomu w stosunku do niego. Dodatkowo na samym początku procedury action() powinieneś wyłączyć komponent, który wyzwolił to zadanie, a w metodzie done() SwingWorkera ponownie go włączyć. Inaczej po wielokrotnym naciśnięciu przycisku miałbyś całe stado okienek dialogowych z różnymi stanami postępu. Na procesorach z małą ilością rdzeni (lub jednordzeniowych) ich prędkości wyrównałyby się i zakończyłyby się w bardzo podobnym czasie (a nie miarowo - po kolei zgodnie z momentami odpalania przycisku wyzwalającego). To taka specyfika pracy wielozadaniowej i symulowania wątków.
Całe działanie po naciśnięciu przycisku działa wtedy tak:
- Odpala się przycisk. Swing dostaje komunikat, szuka właściwego listenera i odpala jego metodę action().
- W action() blokujesz możliwość przyciśnięcia tego przycisku.
- Wraca z action() jeżeli chwilę przedtem wcześniejsze wywołanie action() już się uruchomiło i zablokowało przycisk - można to sprawdzić na dwa sposoby: metodą !isDone() jeżeli dziecko SwingWorkera zostało przypisane jakiejś zmiennej (w tym celu zresztą przypisanie), albo sprawdzić stan blokady przycisku wywołującego (jeżeli zablokowany, to wcześniejsze action() zdążyło się już uruchomić) - wtedy klasa wywiedziona ze SwingWorkera może być wywołana jako anonimowa i nigdzie nie przypisywana. [Uwaga - formalnie odśmiecacz powinien taką klasę usunąć, ale nie zrobi tego nigdy z klasami pracujących wątków. Zrobi to dopiero po zakończeniu metody Done() SwingWorkera.]
- Tworzy się okno dialogu, dodaje go jako dziecko do systemu okien Swinga i wywołuje procedurę wyświetlenia (zlecane jest to Swingowi). Nad tym oknem pełną kontrolę ma Swing, więc gdyby action() teraz zawisło (kręci nim przecież wątek Swing), to również i to nowe okno.
- Odpala się metoda execute() klasy wywiedzionej ze SwingWorkera. Tworzony zostaje nowy wątek odpalający po rożnych działaniach metodę doInBackground(). Sterowanie jednak natychmiast wraca z execute () do action().
- Kończy się metoda action(), której całe wykonanie trwa nanosekundy.
W tym czasie kręci się już Twoja metoda doInBackground() w swoim wątku (a tylko nad nią masz pełną władzę). Swing może już sterować okienkami (w tym utworzonym dialogiem), metodą process() i później done() tego konkretnego obiektu SwingWorkera.
Po powrocie z action() okresowo będzie uruchamiana przez Swing procedura process() Swingworkera. W "magiczny sposób" (przez mechanizmy synchronizacji SwingWorkera) będzie ona dostawała dane z wątku doInBackground() za pośrednictwem metody publish(). Będzie się tak działo aż do zakończenia doInBackground(), co da sygnał SwingWorkerowi do wrzucenia na kolejkę działań Swinga wywołania przez Swing metody done(). W done() zostanie odblokowany przycisk wyzwalający działanie, a po jej zakończeniu odśmiecacz sprzątnie nieaktywny już obiekt wywiedziony ze SwingWorkera. Od tego momentu Cała Twoja aplikacja wraca co stanu początkowego.
Cykl może się rozpocząć od nowa.