Mam główną klasę Javy, w klasie zaczynam nowy wątek, w głównym czeka, aż wątek umrze. W pewnym momencie wyrzucam wyjątek czasu wykonywania z wątku, ale nie mogę złapać wyjątku wyrzuconego z wątku w głównej klasie.
Oto kod:
public class Test extends Thread
{
public static void main(String[] args) throws InterruptedException
{
Test t = new Test();
try
{
t.start();
t.join();
}
catch(RuntimeException e)
{
System.out.println("** RuntimeException from main");
}
System.out.println("Main stoped");
}
@Override
public void run()
{
try
{
while(true)
{
System.out.println("** Started");
sleep(2000);
throw new RuntimeException("exception from thread");
}
}
catch (RuntimeException e)
{
System.out.println("** RuntimeException from thread");
throw e;
}
catch (InterruptedException e)
{
}
}
}
Czy ktoś wie, dlaczego?
java
multithreading
NARU
źródło
źródło
Dzieje się tak, ponieważ wyjątki są lokalne dla wątku, a Twój główny wątek w rzeczywistości nie widzi
run
metody. Sugeruję, abyś przeczytał więcej o tym, jak działa wątkowanie, ale szybko podsumuj: twoje wezwanie dostart
uruchomienia innego wątku, całkowicie niezwiązanego z twoim głównym wątkiem. Wezwaniejoin
po prostu czeka, aż to się stanie. Wyjątek, który jest rzucany w wątku i nigdy nie przechwycony, kończy go, dlategojoin
powraca do głównego wątku, ale sam wyjątek jest tracony.Jeśli chcesz być świadomy tych nieprzechwyconych wyjątków, możesz spróbować tego:
Więcej informacji na temat obsługi nieprzechwyconych wyjątków można znaleźć tutaj .
źródło
Thread.setDefaultUncaughtExceptionHandler()
również wyłapuje wyjątki w wątku „main”To wyjaśnia zmianę stanu wątków w zależności od tego, czy wystąpiły wyjątki, czy nie:
Źródło: http://www-public.imtbs-tsp.eu/~gibson/Teaching/CSC7322/L8-ExceptionsAndThreads.pdf
źródło
Najprawdopodobniej;
Jednak załóżmy, że musisz obsłużyć wyjątek z innego wątku podrzędnego. Użyłbym usługi ExecutorService w ten sposób:
wydruki
źródło
future.get()
czeka ani nie blokuje, aż wątek zakończy wykonywanie?Zapoznaj się z Thread.UncaughtExceptionHandler
Lepszym (alternatywnym) sposobem jest użycie funkcji Callable i Future, aby uzyskać ten sam wynik ...
źródło
Użyj
Callable
zamiast Thread, możesz wywołać,Future#get()
który zgłosi każdy wyjątek, który wyrzucił wywołanie .źródło
Callable.call
jest opakowany w elementExcecutionException
i należy ocenić jego przyczynę.Obecnie łapiesz tylko
RuntimeException
podklasęException
. Jednak Twoja aplikacja może generować inne podklasy Exception . Złap genericException
opróczRuntimeException
Ponieważ wiele rzeczy zostało zmienionych na froncie wątkowania, użyj zaawansowanego API java.
Preferuj zaawansowane API java.util.concurrent do obsługi wielu wątków, takich jak
ExecutorService
lubThreadPoolExecutor
.Możesz dostosować ThreadPoolExecutor do obsługi wyjątków.
Przykład ze strony dokumentacji oracle:
Nadpisanie
Przykładowy kod:
Stosowanie:
Dodałem jeden konstruktor do powyższego kodu jako:
Możesz zmienić ten konstruktor, aby odpowiadał Twoim wymaganiom dotyczącym liczby wątków.
źródło
Napotkałem ten sam problem ... niewielkie obejście (tylko w przypadku implementacji, a nie obiektów anonimowych) ... możemy zadeklarować obiekt wyjątku na poziomie klasy jako null ... następnie zainicjować go w bloku catch dla metody uruchamiania ... jeśli istnieje wystąpił błąd w metodzie uruchamiania, ta zmienna nie będzie zerowa .. możemy wtedy sprawdzić wartość null dla tej konkretnej zmiennej, a jeśli nie jest pusta, wtedy wystąpił wyjątek w wykonaniu wątku.
wywołanie checkForException () po złączeniu ()
źródło
Czy bawiłeś się z setDefaultUncaughtExceptionHandler () i podobnymi metodami klasy Thread? Z interfejsu API: „Ustawiając domyślną procedurę obsługi nieprzechwyconych wyjątków, aplikacja może zmienić sposób obsługi nieprzechwyconych wyjątków (np. Logowanie do określonego urządzenia lub pliku) dla tych wątków, które już zaakceptowałyby jakiekolwiek„ domyślne ”zachowanie dostarczony system. "
Możesz tam znaleźć odpowiedź na swój problem ... powodzenia! :-)
źródło
Również z poziomu Java 8 możesz napisać odpowiedź Dan Cruz jako:
źródło
AtomicReference to także rozwiązanie umożliwiające przekazanie błędu do głównego wątku. Jest to takie samo podejście jak podejście Dana Cruza.
Jedyną zmianą jest to, że zamiast tworzyć zmienną zmienną, możesz użyć AtomicReference, który zrobił to samo za kulisami.
źródło
Przedłużanie prawie zawsze jest złe
Thread
. Nie mogę tego powiedzieć wystarczająco mocno.Zasada wielowątkowości nr 1: Rozszerzanie
Thread
jest nieprawidłowe. *Jeśli
Runnable
zamiast tego zaimplementujesz , zobaczysz swoje oczekiwane zachowanie.produkuje;
* chyba że chcesz zmienić sposób, w jaki Twoja aplikacja używa wątków, co w 99,9% przypadków tego nie robi. Jeśli uważasz, że znajdujesz się w 0,1% przypadków, zapoznaj się z zasadą nr 1.
źródło
Jeśli zaimplementujesz Thread.UncaughtExceptionHandler w klasie, która uruchamia Threads, możesz ustawić, a następnie ponownie zgłosić wyjątek:
Co powoduje następujący wynik:
źródło
Obsługa wyjątków w Thread: Domyślnie metoda run () nie zgłasza żadnego wyjątku, więc wszystkie sprawdzane wyjątki wewnątrz metody run muszą być wychwycone i obsługiwane tylko tam, a dla wyjątków środowiska uruchomieniowego możemy użyć UncaughtExceptionHandler. UncaughtExceptionHandler to interfejs udostępniany przez Javę do obsługi wyjątków w metodzie wykonywania wątków. Możemy więc zaimplementować ten interfejs i przywrócić naszą klasę implementującą z powrotem do obiektu Thread za pomocą metody setUncaughtExceptionHandler (). Ale ten program obsługi musi być ustawiony przed wywołaniem start () na bieżniku.
Jeśli nie ustawimy uncaughtExceptionHandler, ThreadGroup będzie działać jako program obsługi.
Ładne wyjaśnienie podane na http://coder2design.com/thread-creation/#exceptions
źródło
Moje rozwiązanie z RxJava:
źródło
Dla tych, którzy muszą zatrzymać wszystkie uruchomione wątki i ponownie uruchomić je wszystkie, gdy którykolwiek z nich zostanie zatrzymany na wyjątku:
Podsumowując:
Masz główną funkcję, która tworzy wiele wątków, każdy z nich ma UncaughtExceptionHandler, który jest wyzwalany przez dowolny wyjątek wewnątrz wątku. Dodajesz każdy wątek do listy. Jeśli zostanie wyzwolony UncaughtExceptionHandler, przejdzie w pętlę przez List, zatrzyma każdy wątek i ponownie uruchomi główną funkcję odtwarzającą cały Thread.
źródło
Nie możesz tego zrobić, ponieważ to naprawdę nie ma sensu. Jeśli nie wywołałeś
t.join()
, główny wątek może znajdować się w dowolnym miejscu kodu, gdyt
wątek zgłosi wyjątek.źródło