Jak przechwycic zdarzenie ze watek juz nie dziala

0

Czesc - mam takie pytanie. Wyobrazmy sobie ze w klasie A mam metode ktora uruchamia mi N watkow:

 
thread1.start();
thread2.start();
...
threadN.start();

Jak moge w klasie A przechwycic zdarzenie ze ktorys z watkow przestal dzialac?
Jedyne co mi przychodzi do glowy (a co mi sie bardzo nie podoba) to w nieskonczonej petli sprawdzanie isAlive:

 

while(true){
  if(!thread1.isAlive()){

//do the logic here
}

if(!thread2.isAlive()){
//do the logic here
}

...

if(!threadN.isAlive()){
//do the logic here
}

}

Czy ktos z Was ma moze jakas podpowiedz dla mnie jak powinnam to zrobic?

           pzdr,

misty

1

Jeżeli możesz zmieniać kod w klasach wątków to po prostu odpalaj listenera (to jest naiwna metoda, bo kod wykona się w wątku PRZED jego rzeczywistym zakończeniem).

Względnie:

public class CTest {

	private static Runnable t = new Runnable() {

		@Override
		public void run() {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("stop");
		}
	};

	static class Waiter<T> implements Runnable {
		private Future<T> toWait;

		public Waiter(Future<T> toWait) {
			this.toWait = toWait;
		}

		@Override
		public void run() {
			while (!toWait.isDone()) {
				System.out.println("Task not yet completed.");
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
			System.out.println("aaaaaaaaaaaaaaaaaa");
			try {
				System.out.println(toWait.get());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String a[]) throws InterruptedException, ExecutionException {
		ExecutorService e = Executors.newCachedThreadPool();
		FutureTask<String> future = new FutureTask<String>(new Callable<String>() {

			@Override
			public String call() throws Exception {
				t.run();
				return "OK";
			}
		});
		e.execute(new Waiter<String>(future));
		e.execute(future);
		e.shutdown();
	}
}

i zamiast "aaa" dać obiekt obsługujący zdarzenie.

1

A jak watki na koniec by wywolywaly jakas metode? Taki observer pattern, gdzie watki wywoluja threadFinished() na jakims obiekcie, ktory dostaja jako argument.

0

mucka tez mi to przyszlo do glowy. Moglabym dac kod w runie w try-finally - i w finally wywolywac moja metode:

A.watekSieZakonczyl()

i wtedy w A mialabym info o tym zdarzeniu. Spoko, proste rozwiazanie i czytelne. Dzieki!

0

A jeśli "przestał działać" oznacza jakiś RuntimeException?

Mam przeczucie, że zamiast kombinować z wątkami, problem można by rozwiązać za pomocą którejś klasy z: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html

update @misty
Żeby to miało ręce i nogi to pasowałoby jeszcze, żeby wątek nasłuchujący zrobił Thread.join na tym wątku, który zasygnalizował zakończenie. Poza tym nie zapominaj o synchronizacji, bo czasem jest potrzebna.

0

Nie, nie oznacza to RuntimeException. Watek przestanie dzialac jak wywali sie polaczenie. Wtedy z klasy A chcialabym o tym wiedziec i np go zrestartowac. Join to mi tu chyba nie potrzebny? Wydaje mi sie ze opcja z tym ze w bloku finally wywoluje metode ktora powie klasie A co sie stalo to wystarczy..

0

@koziolek

teraz dopiero zauwazylam Twoj komentarz do postu mucka. Piszesz ze jesli w bloku finally wywolam te metode (ktora bedzie informowala moja klase A ze watek sie konczy) to bedzie ona w sumie wywolana przed jego zakonczeniem, czyli w sumie watek bedzie jeszcze dzialal. Ale z drugiej str o przykladzie ktory podales tez napisales ze kod sie wywolam w sumie jeszcze przed zupelnym zakonczeniem watku.. Czyli to w sumie ta sama sytuacja. Czy zatem Twoje podejscie (Twoj przyklad) dalby mi cos wiecej? Wydaje mi sie ze daje mi tylko zbedny kod - bo sprawdzasz tam czy watek sie zakonczyl. A tak na prawde porzadana sytuacja jest to by dzialal zawsze. Ta obsluga tego ze watek sie zakonczy to zwykly Exception (np zerwanie polaczenia). Co teoretycznie nie powinno sie zdarzac. Wiec w sumie to czekanie az watek sie zakonczy to zbedna, nieskonczona petla..

     pzdr,
          misty
0

Niekoniecznie. Pomiędzy tymi rozwiązaniami są dwie różnice.
Pierwsza mniej istotna jest taka, że kod do obsługi zakończenia działania wątku musisz wszczepić w kod realizowany przez wątek. Nie jest to najlepsze rozwiązanie ponieważ mieszasz dwie odpowiedzialności - biznesową i nazwijmy to "administracyjną". Pierwsza związana jest z obsługą zadania, druga z obsługą zakończenia pracy.

Druga różnica jest istotniejsza. W waszym, prostszym, przypadku obsługa zakończenia działania wątku jest realizowana przed jego rzeczywistym zakończeniem. Może to doprowadzić do sytuacji kiedy wątek w części biznesowej zakończy się poprawnie, ale w trakcie obsługi zakończenia wystąpi np. IllegalMonitorStateException ponieważ sięgasz do jakiś zablokowanych zasobów. Tym samym z jednej strony masz "prawidłowo" zakończony wątek, który się wysypał, a z drugiej ciężką do odnalezienia sytuację blokady.
W moim przykładzie mechanizm działania jest trochę inny. Działają tam dwa wątki. Pierwszy to wątek "biznesowy" reprezentowany przez instancję FutureTask, która jest wrapperem na rzeczywisty wątek biznesowy reprezentowany przez zmienną t. W momencie zakończenia działania metody t.run() zwracany jest rezultat - zwykłe "OK", ale może to być np. lista listenerów. Wraz ze zwróceniem wartości wątek kończy swoje działanie. Jednocześnie działa sobie drugi wątek, klasa Waiter, który posiada referencję do pierwszego wątku. W momencie gdy tamten zakończy swoje działanie, metoda isDone() zwróci true, pobiera on rezultat, wypisuje go na konsolę i kończy swoją działalność.
W efekcie choć listenery są wywoływane w osobnym wątku to ich obsługa jest odseparowana od wątku, którego zakończenia nasłuchujemy. Co więcej są one wywoływane już po rzeczywistym zakończeniu tamtego wątku.

Przypomina to sytuację, w której zamiast wierzyć na słowo mechanikowi, że wykonał dobrze pracę wynajmujesz niezależnego eksperta, który ocenia pracę mechanika. Pomimo trochę większego kosztu w postaci dodatkowego wątku "nadzorującego" masz gwarancję, że nie zostaniesz zrobiona w przysłowiowe bambuko.

0

hmm,
no dobra, ale jesli :

 
try{
//dziala sobie watek
}catch(Exception e){
}finally{
  a.powiedzKlasieAZeJuzPrawieKoniec(this);
}

i w klasie A:

 
public void powiedzKlasieAZeJuzPrawieKoniec(Thread mojThread){

  //a tutaj w petli sprawdzam mojThread.isAlive(). i jak dostane ze juz nie jest alive to robie restart
}

bo isAlive i isDone to w sumie chyba tak na prawde to samo, co?

pzdr,
misty

0

No nie... jeżeli wywołasz a.powiedzKlasieAZeJuzPrawieKoniec(this); to jak w środku masz:

whlie(mojThread.isAlive()){}

To zawsze będziesz miała zwracane true ponieważ metoda powiedzKlasieAZeJuzPrawieKoniec będzie wywołana w wątku którego stan sprawdza. Równie dobrze można powiedzieć popełnię samobójstwo jak nie będę żył, wziąć giwerę, stanąć przed lustrem i co pewien czas kontrolować czy się żyje. Skoro żyję to nie popełniam samobójstwa... Oczywiście jak padniesz z głodu i pragnienia należy pociągnąć za spust.

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