0Pricing
Java Academy · Lekcja

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łaniu throwIfFailed()
  • ShutdownOnSuccess: przy wywołaniu result(), 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() lub result()
  • 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
  • joinUntil wymusza 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

  1. Model współbieżności strukturalnej
  2. StructuredTaskScope
  3. Zamykanie po błędzie i powodzeniu
  4. Obsługa błędów i anulowanie
← Powrót do Java Academy