Java Academy · Lektion

ScheduledExecutorService til gentagne opgaver

Planlæg opgaver med faste intervaller eller faste forsinkelser til polling og baggrundsvedligeholdelse.

Lektion 4 af 413 trin

ScheduledExecutorService til gentagne opgaver er en gratis Java Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Java Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Java Academy-kurset indeholder 4 lektioner i alt.

Hvorfor bruge ScheduledExecutorService?

ScheduledExecutorService udvider ExecutorService for at understøtte planlægning af opgaver. Den erstatter de ældre Timer/TimerTask-klasser med en planlægger, der er baseret på en trådpulje og håndterer undtagelser sikkert.

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: Engangsforsinkelse

schedule(task, delay, unit) kører opgaven én gang efter den angivne forsinkelse. Fungerer både med Runnable og 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) kører opgaven gentagne gange med en fast frekvens. Hvis en opgave tager længere tid end perioden, starter den næste udførelse straks efter, at den er færdig (ingen overlapning).

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) venter den angivne forsinkelse EFTER hver opgave er færdig, før den næste startes. God til afstemning, hvor opgavens varighed varierer.

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)

Fast frekvens sammenlignet med fast forsinkelse

Den vigtigste forskel:

  • scheduleAtFixedRate: næste start = seneste start + periode (tidsplan uden drift)
  • scheduleWithFixedDelay: næste start = seneste afslutning + forsinkelse (garanteret mellemrum mellem udførelser)

Brug fixedRate til pulssignaler og fixedDelay til afstemning, hvor opgavens varighed varierer.

ScheduledFuture: Annullering

schedule/scheduleAtFixedRate/scheduleWithFixedDelay returnerer en ScheduledFuture. Kald cancel(false) for at stoppe fremtidige udførelser uden at afbryde den igangværende udførelse:

ScheduledFuture<?> sf = scheduler.scheduleAtFixedRate(
    () -> System.out.println("Heartbeat"), 0, 1, TimeUnit.SECONDS);

// Cancel after 5 seconds
scheduler.schedule(() -> sf.cancel(false), 5, TimeUnit.SECONDS);

Håndtering af undtagelser i planlagte opgaver

Hvis en planlagt opgave kaster en uhåndteret undtagelse, stopper planlæggeren alle gentagne udførelser uden besked. Pak altid koden ind i 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);

Praktisk eksempel: Opdatering af cache

Brug en planlagt opgave til at opdatere en cache med jævne mellemrum:

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); }
}

Genforsøg med gradvist øget ventetid

Implementér gentagne forsøg med eksponentiel backoff ved hjælp af planlagte opgaver:

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);
}

Overvågning: getDelay og getQueue

Undersøg planlæggerens tilstand:

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());
}

Nedlukning og tømning

Ved nedlukning skal du beslutte, om planlagte opgaver stadig skal køre:

ScheduledThreadPoolExecutor ste = (ScheduledThreadPoolExecutor)
    Executors.newScheduledThreadPool(2);

// Cancel scheduled tasks on shutdown (default: false = they run)
ste.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
ste.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);

ste.shutdown();

Hurtigt tjek

En opgave, der er planlagt med scheduleAtFixedRate(..., 1, TimeUnit.SECONDS), tager 3 sekunder at fuldføre. Hvordan håndterer planlæggeren dette?

Opsummering: ScheduledExecutorService

Vigtige pointer:

  • schedule() — udføres én gang efter en forsinkelse
  • scheduleAtFixedRate() — stabil timing uden tidsforskydning (fra start til start)
  • scheduleWithFixedDelay() — garanteret mellemrum (fra afslutning til start)
  • Ufangede undtagelser stopper gentagne opgaver lydløst — pak dem altid ind i try-catch
  • Annullér med ScheduledFuture.cancel(false)
Gratis at komme i gang

Lær Java med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
104
Lektioner
374

Ofte stillede spørgsmål

Er lektionen “ScheduledExecutorService til gentagne opgaver” gratis?

Ja — hele teksten til “ScheduledExecutorService til gentagne opgaver” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Java Academy-kurset, skal du opgradere til CoddyKit PRO. Java Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “ScheduledExecutorService til gentagne opgaver”?

Planlæg opgaver med faste intervaller eller faste forsinkelser til polling og baggrundsvedligeholdelse. Du øver dig i Java Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Java Academy?

Der kræves ingen tidligere erfaring. Java Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “ScheduledExecutorService til gentagne opgaver”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Java Academy-lektion?

Ja. Alle Java Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. ExecutorService og typer af thread pools
  2. Indsendelse af opgaver: Runnable vs. Callable
  3. Future og fejlhåndtering
  4. ScheduledExecutorService til gentagne opgaver
← Tilbage til Java Academy