Java Academy · Les

Taken indienen: Runnable versus Callable

Dien Runnable- en Callable-taken in en haal resultaten op via Future.

Les 2 van 413 stappen

Taken indienen: Runnable versus Callable is een gratis Java Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Java Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Java Academy bevat in totaal 4 lessen.

Runnable tegenover Callable

Twee functionele interfaces vertegenwoordigen taken die bij ExecutorService worden ingediend:

  • Runnable: heeft geen retourwaarde en kan geen gecontroleerde uitzonderingen declareren
  • Callable<V>: retourneert een resultaat van type V en kan gecontroleerde uitzonderingen werpen
import java.util.concurrent.*;

// Runnable — no return value
Runnable r = () -> System.out.println("Running");

// Callable<Integer> — returns a value
Callable<Integer> c = () -> {
    return 42; // or do computation
};

submit(Runnable)

submit(Runnable) retourneert een Future<?>. Als je daarop get() aanroept, wordt null geretourneerd, maar wordt bevestigd dat de taak is voltooid (of wordt een uitzondering geworpen als de taak is mislukt).

ExecutorService pool = Executors.newFixedThreadPool(2);

Future<?> future = pool.submit(() ->
    System.out.println("Task done on " + Thread.currentThread().getName())
);

future.get(); // waits for completion; returns null
System.out.println("Task confirmed complete");
pool.shutdown();

submit(Callable<V>)

submit(Callable) retourneert een Future<V>. Roep future.get() aan om het resultaat op te halen; dit blokkeert totdat de taak is voltooid.

ExecutorService pool = Executors.newFixedThreadPool(2);

Callable<Integer> sumTask = () -> {
    int sum = 0;
    for (int i = 1; i <= 100; i++) sum += i;
    return sum;
};

Future<Integer> future = pool.submit(sumTask);
Integer result = future.get(); // blocks until done
System.out.println("Sum 1..100 = " + result); // 5050
pool.shutdown();

Meerdere Callables indienen met invokeAll

invokeAll() dient een verzameling Callables in en retourneert een List met Futures — alle taken zijn voltooid voordat de methode terugkeert:

List<Callable<String>> tasks = List.of(
    () -> "Result A",
    () -> "Result B",
    () -> "Result C"
);

ExecutorService pool = Executors.newFixedThreadPool(3);
List<Future<String>> futures = pool.invokeAll(tasks);

for (Future<String> f : futures) {
    System.out.println(f.get());
}
pool.shutdown();

invokeAny: eerste geslaagde resultaat

invokeAny() dient een verzameling Callables in en retourneert het resultaat van de eerste taak die succesvol wordt voltooid; de overige taken worden geannuleerd:

List<Callable<String>> candidates = List.of(
    () -> { Thread.sleep(200); return "Slow"; },
    () -> { Thread.sleep(50);  return "Fast"; },
    () -> { Thread.sleep(100); return "Medium"; }
);

ExecutorService pool = Executors.newFixedThreadPool(3);
String winner = pool.invokeAny(candidates);
System.out.println("First: " + winner); // Fast
pool.shutdown();

execute() tegenover submit()

execute(Runnable) start de taak zonder op het resultaat te wachten — er wordt geen Future geretourneerd en uitzonderingen gaan verloren tenzij je een handler voor niet-afgevangen uitzonderingen toevoegt. submit() verpakt de taak in een Future, waarbij uitzonderingen worden vastgelegd zodat je ze via get() kunt ophalen.

ExecutorService pool = Executors.newFixedThreadPool(2);

// execute: exception silently lost
pool.execute(() -> { throw new RuntimeException("Oops!"); });

// submit: exception captured in Future
Future<?> f = pool.submit(() -> { throw new RuntimeException("Oops!"); });
try {
    f.get();
} catch (ExecutionException e) {
    System.out.println("Caught: " + e.getCause().getMessage());
}
pool.shutdown();

Callable met gecontroleerde uitzonderingen

In tegenstelling tot Runnable kan Callable gecontroleerde uitzonderingen werpen — daardoor is het geschikt voor I/O- en databasebewerkingen:

Callable<String> dbQuery = () -> {
    // This compiles fine — checked exception is declared on Callable.call()
    if (Math.random() < 0.5) throw new java.sql.SQLException("DB error");
    return "row data";
};

Future<String> f = pool.submit(dbQuery);
try {
    String data = f.get();
} catch (ExecutionException e) {
    if (e.getCause() instanceof java.sql.SQLException) {
        System.out.println("DB failed: " + e.getCause().getMessage());
    }
}

Onafhankelijke berekeningen parallel uitvoeren

Gebruik meerdere Callable-indieningen om onafhankelijke berekeningen parallel uit te voeren:

ExecutorService pool = Executors.newFixedThreadPool(4);

Future<Long> sumFuture  = pool.submit(() -> LongStream.rangeClosed(1,1_000_000).sum());
Future<Long> prodFuture = pool.submit(() -> LongStream.rangeClosed(1,20).reduce(1L, (a,b)->a*b));

long sum  = sumFuture.get();
long prod = prodFuture.get();
System.out.println("Sum: " + sum + ", 20!: " + prod);
pool.shutdown();

Resultaten van Callables samenvoegen

Dien veel taken in en voeg de resultaten samen zodra alle taken zijn voltooid:

int N = 8;
ExecutorService pool = Executors.newFixedThreadPool(N);
List<Future<Integer>> futures = new ArrayList<>();

for (int i = 0; i < N; i++) {
    final int chunk = i;
    futures.add(pool.submit(() -> chunk * chunk)); // i^2
}

int total = 0;
for (Future<Integer> f : futures) total += f.get();
System.out.println("Sum of squares: " + total);
pool.shutdown();

Tijdslimiet voor Callable

Geef een tijdslimiet door aan future.get(timeout, unit) om te voorkomen dat je voor altijd blijft wachten:

Future<String> f = pool.submit(() -> {
    Thread.sleep(5000); // slow task
    return "done";
});
try {
    String result = f.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    System.out.println("Task timed out");
    f.cancel(true); // interrupt the task
} catch (ExecutionException e) {
    System.out.println("Task failed: " + e.getCause());
}

Aanbevolen werkwijzen

Samenvatting van aanbevolen werkwijzen:

  • Gebruik submit() in plaats van execute() — uitzonderingen worden vastgelegd
  • Gebruik Callable wanneer je een retourwaarde of gecontroleerde uitzonderingen nodig hebt
  • Roep altijd future.get() aan met een tijdslimiet
  • Gebruik invokeAll voor batchverwerking en invokeAny wanneer het eerste antwoord moet winnen
  • Sluit de pool altijd af

Korte controle

Wat is het belangrijkste voordeel van Callable ten opzichte van Runnable?

Samenvatting: Runnable tegenover Callable

Belangrijkste punten:

  • Runnable: void, geen gecontroleerde uitzonderingen; submit retourneert Future<?> met null
  • Callable: retourneert V en kan gecontroleerde uitzonderingen werpen; submit retourneert Future<V>
  • invokeAll: dient een batch in en wacht totdat alles is voltooid
  • invokeAny: retourneert het eerste geslaagde resultaat en annuleert de rest
  • Gebruik altijd submit() om uitzonderingen vast te leggen
Gratis beginnen

Leer Java met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
104
Lessen
374

Veelgestelde vragen

Is de les “Taken indienen: Runnable versus Callable” gratis?

Ja — de volledige tekst van “Taken indienen: Runnable versus Callable” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Java Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Java Academy bevat in totaal 4 lessen.

Wat leer ik in “Taken indienen: Runnable versus Callable”?

Dien Runnable- en Callable-taken in en haal resultaten op via Future. Je oefent met Java Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Java Academy te beginnen?

Ervaring vooraf is niet nodig. Java Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Taken indienen: Runnable versus Callable”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Java Academy?

Ja. Elke les over Java Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. ExecutorService en typen threadpools
  2. Taken indienen: Runnable versus Callable
  3. Future en foutafhandeling
  4. ScheduledExecutorService voor terugkerende taken
← Terug naar Java Academy