0Pricing
Java Academy · Lekcja

Future i obsługa błędów

Używaj Future.get z limitami czasu, obsługuj ExecutionException i anuluj uruchomione zadania.

Future i obsługa błędów to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 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.

Czym jest Future?

Obiekt Future<V> reprezentuje oczekujący wynik asynchronicznego obliczenia. Udostępnia metody do sprawdzania ukończenia, oczekiwania na wynik i obsługi błędów.

import java.util.concurrent.*;

ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> future = pool.submit(() -> {
    Thread.sleep(1000);
    return 42;
});

System.out.println("Is done? " + future.isDone()); // false
Integer result = future.get(); // blocks
System.out.println("Result: " + result); // 42
pool.shutdown();

future.get() z limitem czasu

Zawsze preferuj wariant z limitem czasu, aby zapobiec niekończącemu się oczekiwaniu:

try {
    Integer result = future.get(5, TimeUnit.SECONDS);
    System.out.println(result);
} catch (TimeoutException e) {
    System.out.println("Timed out");
    future.cancel(true); // interrupt the task
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} catch (ExecutionException e) {
    System.out.println("Task threw: " + e.getCause());
}

ExecutionException

Jeśli zadanie zgłosiło wyjątek, future.get() opakowuje go w ExecutionException. Usuń opakowanie za pomocą getCause():

Future<String> failing = pool.submit(() -> {
    throw new IllegalArgumentException("bad input");
});

try {
    failing.get();
} catch (ExecutionException e) {
    Throwable cause = e.getCause();
    System.out.println(cause.getClass().getSimpleName()); // IllegalArgumentException
    System.out.println(cause.getMessage()); // bad input
}

Anulowanie obiektu Future

cancel(mayInterruptIfRunning) próbuje anulować zadanie. Zwraca true, jeśli się powiedzie. Jeśli mayInterruptIfRunning ma wartość true, do działającego wątku wysyłane jest żądanie przerwania.

Future<String> f = pool.submit(() -> {
    try {
        Thread.sleep(10_000); // long task
        return "done";
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return "interrupted";
    }
});

boolean cancelled = f.cancel(true); // send interrupt
System.out.println("Cancelled: " + cancelled); // true
System.out.println("Is cancelled: " + f.isCancelled()); // true

isCancelled a isDone

isDone() zwraca true, jeśli zadanie zakończyło się normalnie, zgłosiło wyjątek lub zostało anulowane. isCancelled() zwraca true tylko wtedy, gdy zadanie zostało anulowane.

// After cancel:
System.out.println(f.isDone());       // true
System.out.println(f.isCancelled()); // true

// After normal completion:
Future<Integer> done = pool.submit(() -> 5);
done.get(); // wait
System.out.println(done.isDone());       // true
System.out.println(done.isCancelled()); // false

CompletionService dla wyników dostępnych jako pierwsze

ExecutorCompletionService opakowuje pulę i udostępnia metodę take() do pobierania kolejnego ukończonego obiektu Future (w kolejności ukończenia, a nie przesłania):

ExecutorCompletionService<Integer> cs =
    new ExecutorCompletionService<>(pool);

for (int i = 0; i < 5; i++) {
    final int delay = 5 - i; // submit fastest last
    cs.submit(() -> { Thread.sleep(delay * 100); return delay; });
}

for (int i = 0; i < 5; i++) {
    Future<Integer> f = cs.take(); // next completed
    System.out.println(f.get());
}

Bezpieczna obsługa wielu obiektów Future

Podczas zbierania wyników z wielu obiektów Future iteruj po nich i obsługuj wyjątki dla każdego z osobna:

List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 5; i++) {
    final int id = i;
    futures.add(pool.submit(() ->
        id % 2 == 0 ? "ok_" + id : (() -> { throw new RuntimeException("fail_"+id); }).get()
    ));
}

for (Future<String> f : futures) {
    try {
        System.out.println(f.get());
    } catch (ExecutionException e) {
        System.out.println("Error: " + e.getCause().getMessage());
    }
}

Future.get() po wyłączeniu puli

Przesłanie zadania po shutdown() zgłasza RejectedExecutionException. Jednak obiekty Future przesłane PRZED wyłączeniem puli nadal można pobierać po jej wyłączeniu:

ExecutorService pool2 = Executors.newFixedThreadPool(2);
Future<Integer> f = pool2.submit(() -> 99);
pool2.shutdown(); // no new tasks

// Still valid — task was submitted before shutdown:
System.out.println(f.get()); // 99

try {
    pool2.submit(() -> 0); // throws!
} catch (RejectedExecutionException e) {
    System.out.println("Pool shut down");
}

FutureTask: ręczny Future

FutureTask<V> implementuje zarówno Runnable, jak i Future<V> — jest przydatny, gdy potrzebują Państwo obiektu Future bez ExecutorService:

FutureTask<String> task = new FutureTask<>(() -> "computed");
new Thread(task).start(); // run in any thread
System.out.println(task.get()); // computed

Wzorzec ponawiania prób z Future

Zaimplementuj prostą logikę ponawiania prób wokół future.get():

Future<String> future = pool.submit(() -> {
    if (Math.random() < 0.7) throw new RuntimeException("transient error");
    return "success";
});

for (int attempt = 0; attempt < 3; attempt++) {
    try {
        System.out.println(future.get());
        break;
    } catch (ExecutionException e) {
        System.out.println("Attempt " + (attempt+1) + " failed");
        if (attempt == 2) throw e;
        future = pool.submit(() -> "retry"); // resubmit
    }
}

Ograniczenia Future

java.util.concurrent.Future ma następujące ograniczenia:

  • Brak wywołań zwrotnych — konieczne jest blokowanie za pomocą get()
  • Nie można łączyć transformacji w łańcuch
  • Nie można łączyć wielu obiektów Future

W kolejnym kursie użyj CompletableFuture do reaktywnego, nieblokującego komponowania operacji.

Szybkie sprawdzenie

Zadanie zgłasza wyjątek. Jaki wyjątek zostanie zgłoszony po wywołaniu future.get()?

Podsumowanie: Future i obsługa błędów

Najważniejsze informacje:

  • future.get() blokuje wykonanie; zawsze używaj wariantu z limitem czasu
  • ExecutionException opakowuje wyjątki zadań; usuń opakowanie za pomocą getCause()
  • cancel(true) wysyła żądanie przerwania; isDone/isCancelled służą do sprawdzania stanu
  • ExecutorCompletionService.take() pobiera obiekty Future w kolejności ukończenia
  • FutureTask implementuje zarówno Runnable, jak i Future

Często zadawane pytania

Czy lekcja „Future i obsługa błędów” jest bezpłatna?

Tak — pełny tekst „Future i obsługa błędów” 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 „Future i obsługa błędów”?

Używaj Future.get z limitami czasu, obsługuj ExecutionException i anuluj uruchomione zadania. Ć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 3 z 4.

Ile czasu zajmuje lekcja „Future i obsługa błędów”?

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. ExecutorService i typy pul wątków
  2. Przesyłanie zadań: Runnable a Callable
  3. Future i obsługa błędów
  4. ScheduledExecutorService do zadań cyklicznych
← Powrót do Java Academy