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()); // trueisCancelled 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()); // falseCompletionService 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()); // computedWzorzec 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
- ExecutorService i typy pul wątków
- Przesyłanie zadań: Runnable a Callable
- Future i obsługa błędów
- ScheduledExecutorService do zadań cyklicznych