Obsługa błędów i anulowanie
Czyste propagowanie błędów
Obsługa błędów i anulowanie to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Błędy w drzewie zadań
Gdy podzadania działają współbieżnie, błędy mogą wystąpić w dowolnej gałęzi. Współbieżność strukturalna zapewnia zdyscyplinowany sposób propagowania tych błędów do zadania nadrzędnego.
Ta lekcja obejmuje wyjątki, anulowanie, przerwania i limity czasu.
Gdzie pojawiają się wyjątki
Podzadanie, które zgłasza wyjątek, nie powoduje natychmiastowego zakończenia programu. Wyjątek jest przechwytywany na uchwycie Subtask. Miejsce jego pojawienia się zależy od zasady:
ShutdownOnFailure: przy wywołaniuthrowIfFailed()ShutdownOnSuccess: przy wywołaniuresult(), jeśli żadne podzadanie nie zakończyło się powodzeniem
Propagowanie za pomocą throwIfFailed
W tym przykładzie podzadanie kończy się niepowodzeniem. throwIfFailed() ponownie zgłasza wyjątek opakowany w ExecutionException, który przechwytujemy w metodzie main.
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> "ok");
scope.fork(() -> { throw new RuntimeException("boom"); });
scope.join();
scope.throwIfFailed();
System.out.println("never reached");
} catch (ExecutionException e) {
System.out.println("Caught cause: " + e.getCause().getMessage());
}
}
}Mapowanie na własny wyjątek
throwIfFailed przyjmuje funkcję, która opakowuje przyczynę we własny typ wyjątku, dzięki czemu API pozostaje przejrzyste.
import java.util.concurrent.StructuredTaskScope;
class DataAccessException extends Exception {
DataAccessException(Throwable cause) { super(cause); }
}
public class Main {
public static void main(String[] args) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> { throw new RuntimeException("db down"); });
scope.join();
scope.throwIfFailed(DataAccessException::new);
} catch (DataAccessException e) {
System.out.println("Wrapped: " + e.getCause().getMessage());
}
}
}Automatyczne anulowanie
Gdy jedno z podzadań kończy się niepowodzeniem w ramach ShutdownOnFailure, zakres anuluje podzadania równoległe, przerywając ich wątki. Nie trzeba samodzielnie pisać kodu obsługującego anulowanie.
Zapobiega to marnowaniu pracy i pozostawaniu zadań bez nadzoru.
Mechanizmem jest przerwanie
Anulowanie działa przez przerwanie wirtualnego wątku podzadania. Kod współpracujący z mechanizmem anulowania powinien:
- Pozwalać, aby wywołania blokujące zgłaszały
InterruptedException - Okresowo sprawdzać
Thread.currentThread().isInterrupted()w długich pętlach
Reagowanie na przerwanie
To zadanie sprawdza flagę przerwania w pętli, dzięki czemu może wcześniej się zatrzymać, gdy zakres zostanie zamknięty.
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(() -> {
long count = 0;
while (!Thread.currentThread().isInterrupted()) {
count++;
if (count == 1_000_000) break;
}
System.out.println("Stopped after " + count + " iterations");
});
t.join();
}
}Terminy z joinUntil
Aby ograniczyć łączny czas działania, należy użyć joinUntil(Instant). Jeśli termin upłynie, zanim wszystkie podzadania się zakończą, metoda zgłosi TimeoutException, a zakres zamknie pozostałe podzadania.
Schemat przykładu z limitem czasu
Typowe rozdzielanie pracy z zabezpieczeniem przed przekroczeniem limitu czasu wygląda tak. Termin dotyczy całej grupy, a nie każdego podzadania osobno.
import java.time.*;
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
scope.fork(() -> "fast");
scope.joinUntil(Instant.now().plus(Duration.ofSeconds(2)));
scope.throwIfFailed();
System.out.println("Completed within deadline");
} catch (TimeoutException e) {
System.out.println("Deadline exceeded");
} catch (ExecutionException e) {
System.out.println("A subtask failed");
}
}
}Zawsze sprawdzaj ponownie po join
Dyscyplina polega na tym, aby po wywołaniu join() (lub joinUntil) zawsze wywołać throwIfFailed() albo odczytać result() przed uznaniem dowolnej wartości podzadania za poprawną. Pominięcie tego kroku może ukryć błędy.
Gwarantowane poprawne zamknięcie
Niezależnie od tego, jak kończy się zakres — normalnie, wskutek błędu czy przekroczenia limitu czasu — zamknięcie bloku try-with-resources gwarantuje, że każdy wątek podzadania zakończył działanie. Nie ma wycieków ani osieroconych zadań.
Szybkie sprawdzenie
Proszę przypomnieć sobie, jak zatrzymywane są równoległe podzadania.
Podsumowanie
Poznali Państwo obsługę błędów i anulowanie:
- Wyjątki pojawiają się przy wywołaniu
throwIfFailed()lubresult() - Przyczyny można mapować na własne wyjątki za pomocą
throwIfFailed(mapper) - Anulowanie działa przez przerwanie wątku; należy pisać zadania współpracujące z tym mechanizmem
joinUntilwymusza termin dla całej grupy- Zamknięcie zakresu zawsze sprząta zasoby
To kończy kurs współbieżności strukturalnej.
Często zadawane pytania
Czy lekcja „Obsługa błędów i anulowanie” jest bezpłatna?
Tak — pełny tekst „Obsługa błędów i anulowanie” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Obsługa błędów i anulowanie”?
Czyste propagowanie błędów Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Obsługa błędów i anulowanie”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Model współbieżności strukturalnej
- StructuredTaskScope
- Zamykanie po błędzie i powodzeniu
- Obsługa błędów i anulowanie