ScheduledExecutorService do zadań cyklicznych
Planuj zadania ze stałą częstotliwością lub stałymi opóźnieniami na potrzeby odpytywania i prac konserwacyjnych w tle.
ScheduledExecutorService do zadań cyklicznych 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.
Dlaczego używać ScheduledExecutorService?
ScheduledExecutorService rozszerza ExecutorService, aby obsługiwać planowanie zadań. Zastępuje starsze klasy Timer/TimerTask bezpiecznym pod względem wyjątków harmonogramem opartym na puli wątków.
import java.util.concurrent.*;
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// One-shot delay
scheduler.schedule(
() -> System.out.println("Runs once after 3 seconds"),
3, TimeUnit.SECONDS
);
// Don't forget to shut down eventually:
// scheduler.shutdown();schedule: jednorazowe opóźnienie
schedule(task, delay, unit) uruchamia zadanie jeden raz po upływie określonego opóźnienia. Działa zarówno z Runnable, jak i Callable:
ScheduledExecutorService s = Executors.newScheduledThreadPool(1);
// Runnable:
ScheduledFuture<?> sf1 = s.schedule(
() -> System.out.println("Runnable fired!"), 2, TimeUnit.SECONDS);
// Callable:
ScheduledFuture<Integer> sf2 = s.schedule(
() -> { System.out.println("Callable fired!"); return 42; },
2, TimeUnit.SECONDS);
System.out.println(sf2.get()); // 42 (after 2 seconds)scheduleAtFixedRate
scheduleAtFixedRate(task, initialDelay, period, unit) uruchamia zadanie wielokrotnie ze stałą częstotliwością. Jeśli wykonanie zadania trwa dłużej niż okres, następne wykonanie rozpoczyna się natychmiast po jego zakończeniu (bez nakładania się wykonań).
ScheduledExecutorService s = Executors.newScheduledThreadPool(1);
AtomicInteger count = new AtomicInteger();
ScheduledFuture<?> sf = s.scheduleAtFixedRate(
() -> System.out.println("Tick " + count.incrementAndGet()),
0, // initial delay
1, // period
TimeUnit.SECONDS
);
Thread.sleep(5000);
sf.cancel(false); // stop after 5 ticks
s.shutdown();scheduleWithFixedDelay
scheduleWithFixedDelay(task, initialDelay, delay, unit) po każdym zakończeniu zadania czeka przez określone opóźnienie, zanim rozpocznie następne. Dobrze nadaje się do odpytywania, gdy czas trwania zadania jest zmienny.
s.scheduleWithFixedDelay(
() -> {
System.out.println("Polling... " + Instant.now());
// variable-length polling task
},
0, // no initial delay
5, // 5-second gap AFTER each completion
TimeUnit.SECONDS
);
// Next execution = task end + 5 seconds (not task start)Stała częstotliwość a stałe opóźnienie
Najważniejsza różnica:
- scheduleAtFixedRate: następne rozpoczęcie = ostatnie rozpoczęcie + okres (odstępy czasowe bez narastającego przesunięcia)
- scheduleWithFixedDelay: następne rozpoczęcie = ostatnie zakończenie + opóźnienie (gwarantowany odstęp między wykonaniami)
Używaj fixedRate dla sygnałów heartbeat, a fixedDelay do odpytywania, gdy czas trwania zadania jest zmienny.
ScheduledFuture: anulowanie
schedule/scheduleAtFixedRate/scheduleWithFixedDelay zwracają obiekt ScheduledFuture. Wywołaj cancel(false), aby zatrzymać przyszłe wykonania bez przerywania aktualnie wykonywanego zadania:
ScheduledFuture<?> sf = scheduler.scheduleAtFixedRate(
() -> System.out.println("Heartbeat"), 0, 1, TimeUnit.SECONDS);
// Cancel after 5 seconds
scheduler.schedule(() -> sf.cancel(false), 5, TimeUnit.SECONDS);Obsługa wyjątków w zadaniach zaplanowanych
Jeśli zaplanowane zadanie zgłosi nieprzechwycony wyjątek, harmonogram po cichu zatrzymuje wykonywanie cykliczne — kolejne wykonania nie nastąpią. Zawsze używaj try-catch:
scheduler.scheduleAtFixedRate(() -> {
try {
// risky work
if (Math.random() < 0.3) throw new RuntimeException("transient");
System.out.println("Success");
} catch (Exception e) {
System.err.println("Task error: " + e.getMessage());
// task continues to run on next interval
}
}, 0, 2, TimeUnit.SECONDS);Praktyczny przykład: odświeżanie pamięci podręcznej
Użyj zaplanowanego zadania, aby okresowo odświeżać pamięć podręczną:
class PriceCache {
private volatile Map<String, Double> prices = new HashMap<>();
PriceCache(ScheduledExecutorService scheduler) {
scheduler.scheduleAtFixedRate(this::refresh, 0, 30, TimeUnit.SECONDS);
}
private void refresh() {
System.out.println("Refreshing prices...");
// prices = fetchFromDatabase();
}
Double getPrice(String symbol) { return prices.get(symbol); }
}Praktyczny przykład: ponawianie prób z narastającym opóźnieniem
Implementacja ponawiania prób z wykładniczym zwiększaniem opóźnienia przy użyciu zadań planowanych:
void retryWithBackoff(Runnable task, int maxRetries, ScheduledExecutorService s) {
AtomicInteger attempts = new AtomicInteger(0);
long[] delay = {1}; // seconds
Runnable wrapper = new Runnable() {
public void run() {
try {
task.run();
} catch (Exception e) {
int n = attempts.incrementAndGet();
if (n < maxRetries) {
delay[0] *= 2;
s.schedule(this, delay[0], TimeUnit.SECONDS);
} else System.err.println("Max retries reached");
}
}
};
s.execute(wrapper);
}Monitorowanie: getDelay i getQueue
Inspekcja stanu harmonogramu:
ScheduledFuture<?> sf = scheduler.schedule(() -> {}, 10, TimeUnit.SECONDS);
System.out.println("Delay remaining: " + sf.getDelay(TimeUnit.SECONDS) + "s");
// ThreadPoolExecutor provides queue inspection:
if (scheduler instanceof ScheduledThreadPoolExecutor ste) {
System.out.println("Queue size: " + ste.getQueue().size());
}Zamykanie i opróżnianie
Podczas zamykania należy zdecydować, czy zaplanowane zadania powinny nadal być wykonywane:
ScheduledThreadPoolExecutor ste = (ScheduledThreadPoolExecutor)
Executors.newScheduledThreadPool(2);
// Cancel scheduled tasks on shutdown (default: false = they run)
ste.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
ste.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
ste.shutdown();Szybkie sprawdzenie
Zadanie zaplanowane za pomocą scheduleAtFixedRate(..., 1, TimeUnit.SECONDS) trwa 3 sekundy. Jak harmonogram obsłuży taką sytuację?
Podsumowanie: ScheduledExecutorService
Najważniejsze informacje:
- schedule() — jednorazowe wykonanie z opóźnieniem
- scheduleAtFixedRate() — taktowanie bez dryfu (od rozpoczęcia do rozpoczęcia)
- scheduleWithFixedDelay() — gwarantowana przerwa (od zakończenia do rozpoczęcia)
- Nieobsłużone wyjątki po cichu zatrzymują cykliczne zadania — należy zawsze opakować je w try-catch
- Anulowanie za pomocą ScheduledFuture.cancel(false)
Często zadawane pytania
Czy lekcja „ScheduledExecutorService do zadań cyklicznych” jest bezpłatna?
Tak — pełny tekst „ScheduledExecutorService do zadań cyklicznych” 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 „ScheduledExecutorService do zadań cyklicznych”?
Planuj zadania ze stałą częstotliwością lub stałymi opóźnieniami na potrzeby odpytywania i prac konserwacyjnych w tle. Ć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 „ScheduledExecutorService do zadań cyklicznych”?
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