Thread i powiadamianie Listenerów

0

Zastanawiam się nad zatrudnieniem wątków do wykonania kilku zadań i chciał bym aby wątki powiadamiały moją klasę o zakończeniu swojej pracy. W klasie dodałem implementację actionPerformed ale nie wiem jak zapytać google o to, co dodać w klasie wątku, żeby powiadamiał moją metodę actionPerformed. Ciągle dostaję od wujka google jak dodać action listenera do komponentów SWING a mnie to nie interesuje i nie chcę dziedziczyć w wątku po Component.

Wobec tego pytanie. Jak zaimplementować w klasie consumerThread powiadamianie actionListenera w innej klasie tej samej paczki.

kod wątku :

public class consumerThread implements Runnable {

	start base;     //referencja do klasy startującej wątek

	public consumerThread(start base) {
		this.base = base;
	}

	@Override
	public void run() {
                  // jakaś tam implementacja
	}

        private workDone (){

        }

} 

kod klasy wywołującej wątek :

public class start implements ActionListener{

	public void startuj() {
		consumerThread th1 = new consumerThread(this);
		Thread consumer = new Thread(th1);
		producerThread th2 = new producerThread(this);
		Thread producer = new Thread(th2);
		consumer.start();
		producer.start();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.err.println(e.getSource());
	}
}

 
0

Startuj jako wątki nie obiekty Thread, ale swoje klasy (Thread mogą być w kompozycji jako obiekty wewnętrzne, albo dziedzicząc). Wtedy na koniec działania takiego spreparowanego wątku możesz sobie wywołać Co będzie Ci się podobało (np. actionPerformed jakiegoś obiektu). Są jeszcze inne rozwiązania (np. SwingWorker i jego metoda done), ale to jest chyba najprostsze do załapania.

0

Nie starczyło miesca w komentarzu, więc muszę napiać tu :)
Wątki są zarządzane przez system operacyjny. Metoda start() tworzy i startuje wątek w systemie (za pośrednictwem JVM), jednak zatrzymanie wątku przez metody stop() lub suspend() (są oznaczone @depracted) są jedynie sugestią do systemu i nie działała to zawsze, bo decyduje o tym specyfika systemu (czasami nie opłaca się zabijać pojedyńczych wątku, a całą ich pulę). Tym bardziej dojście do końca metody tun() nie determinuje, że wątek zostanie fizycznie zniszczony. Programista powinien jedynie zatroszczyć się o to, aby wątek nie zjadał zasobów CPU, kiedy wykona swoje zadanie. Jak zaleca się to robić?

 
@Override
public void run()
{
  flaga = true;
  while(flaga)
  {
     //praca wątku
  }
}

public void terminate()
{
   flaga = false;
}

Teraz kiedy wiemy, że wątek nie powinien już pracować wywołujemy:

thread.terminate();
thread.join(); // aktualny wątek czeka aż thread zakończy pracę (nie musi się to wiązać z fizycznym końcem życia wątku)

Drugim podejściem jest użycie przerwań. W pętli głównej sprawdza się czy ktoś przypadkiem nie wywołał przerwania na naszym wątku. Jeśli tak to wyskakujemy z pętli. To podejście może być lepsze ponieważ przerwanie wątku działa natychmiastowo nawet jeśli wątek np. śpi (metoda sleep()).

0
 
@Override
public void run()
{
  flaga = true;
  while(flaga)
  {
     //praca wątku
  }
}
 
public void terminate()
{
   flaga = false;
}
 
 

Czyli widzę, że podejście podobne jak w BackgroundWorkerze .NET-u. Wątek pracuje w pętli while.

W .NET miałem problem w mojej aplikacji z dostępem do obiektu typu Image który był wykorzystywany przez GUI ("ImageBox-a") a w wątku chciałem odczytać aktualny stan Image, narysować na nim ramkę zaznaczenia i repaitnąć go na ImageBoxie. Działała metoda Lock albo MonitorEnter, już nie pamiętam, z .NET ( odpowiednik synchronized(lock) z Javy ) ale od czasu do czasu Lock nie nadążał z blokowaniem i trzepało exceptionami "Image jest używany przez inny proces".

Czy w Javie również natknę się na to, że pomimo umieszczenia kodu w bloku synchronized (lock) , JVM wyrzuci exception ?

0

To raczej nie specyfika języka, a zadania które chciałeś wywołać.
Ciężko jest zablokować obiekt, który jest nieustannie używany lub ma wysoki priorytet (repaint wywoływane przez framework) .
Nie powinno się modyfikować kontrolek z "innego wątku".
Jeśli Twój "inny wątek" wykonuje pewną pracę, która zmienia stan aplikacji i wymaga to odświeżenia UI, powiadom wątek główny i oddeleguj tą robotę do wątku UI. Tą logikę można zrobić samemu, ale niemal wszystkie popularne platformy mają gotowe mechanizmy w stylu BackgroundWorker, SwingWorker czy Androidowa funkcja klasy View postInvalidate(), która pozwala odrysować obiekt z "innego wątku"

1 użytkowników online, w tym zalogowanych: 0, gości: 1