0Pricing
Java Academy · Lektion

Aufgaben übermitteln: Runnable vs. Callable

Übermitteln Sie Runnable- und Callable-Aufgaben und rufen Sie Ergebnisse über Future ab.

Aufgaben übermitteln: Runnable vs. Callable ist eine kostenlose Java Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Java Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Runnable vs. Callable

Zwei funktionale Schnittstellen repräsentieren Aufgaben, die an ExecutorService übergeben werden:

  • Runnable: kein Rückgabewert, kann keine geprüften Ausnahmen deklarieren
  • Callable<V>: gibt ein Ergebnis vom Typ V zurück und kann geprüfte Ausnahmen auslösen
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) gibt ein Future<?> zurück. Der Aufruf von get() darauf gibt null zurück, bestätigt aber, dass die Aufgabe abgeschlossen wurde, oder löst eine Ausnahme aus, wenn sie fehlgeschlagen ist.

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) gibt ein Future<V> zurück. Rufen Sie future.get() auf, um das Ergebnis abzurufen; der Aufruf blockiert, bis die Aufgabe abgeschlossen ist.

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

Mehrere Callables mit invokeAll übergeben

invokeAll() übergibt eine Sammlung von Callables und gibt eine Liste von Futures zurück – alle Aufgaben sind abgeschlossen, bevor die Methode zurückkehrt:

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: Erstes erfolgreiches Ergebnis

invokeAny() übergibt eine Sammlung von Callables und gibt das Ergebnis der ersten erfolgreich abgeschlossenen Aufgabe zurück. Die übrigen Aufgaben werden abgebrochen:

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() vs. submit()

execute(Runnable) führt eine Aufgabe aus, ohne auf ihr Ergebnis zu warten – ein Future wird nicht zurückgegeben. Ausnahmen gehen verloren, sofern Sie keinen Handler für nicht abgefangene Ausnahmen hinzufügen. submit() verpackt die Aufgabe in ein Future und erfasst Ausnahmen, die über get() abgerufen werden können.

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 mit geprüften Ausnahmen

Im Gegensatz zu Runnable kann Callable geprüfte Ausnahmen auslösen und eignet sich daher besonders für I/O- und Datenbankoperationen:

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

Unabhängige Berechnungen parallel ausführen

Verwenden Sie mehrere Callable-Übergaben, um unabhängige Berechnungen parallel auszuführen:

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

Ergebnisse von Callable-Aufgaben zusammenführen

Übergeben Sie viele Aufgaben und führen Sie die Ergebnisse zusammen, sobald alle abgeschlossen sind:

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

Timeout bei Callable

Übergeben Sie an future.get(timeout, unit) ein Timeout, damit nicht unbegrenzt gewartet wird:

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

Bewährte Vorgehensweisen

Zusammenfassung der bewährten Vorgehensweisen:

  • Verwenden Sie submit() statt execute() – Ausnahmen werden erfasst
  • Verwenden Sie Callable, wenn Sie einen Rückgabewert oder geprüfte Ausnahmen benötigen
  • Rufen Sie future.get() stets mit einem Timeout auf
  • Verwenden Sie invokeAll für die Stapelverarbeitung und invokeAny für die zuerst erfolgreiche Antwort
  • Fahren Sie den Pool stets herunter

Kurzer Test

Was ist der entscheidende Vorteil von Callable gegenüber Runnable?

Zusammenfassung: Runnable vs. Callable

Die wichtigsten Punkte:

  • Runnable: void, keine geprüften Ausnahmen; submit gibt Future<?> mit dem Wert null zurück
  • Callable: gibt V zurück, kann geprüfte Ausnahmen auslösen; submit gibt Future<V> zurück
  • invokeAll: übergibt einen Stapel von Aufgaben und wartet, bis alle abgeschlossen sind
  • invokeAny: gibt das erste erfolgreiche Ergebnis zurück und bricht die übrigen Aufgaben ab
  • Verwenden Sie stets submit() zur Erfassung von Ausnahmen

Häufig gestellte Fragen

Ist die Lektion „Aufgaben übermitteln: Runnable vs. Callable“ kostenlos?

Ja — der vollständige Text von „Aufgaben übermitteln: Runnable vs. Callable“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Java Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Aufgaben übermitteln: Runnable vs. Callable“?

Übermitteln Sie Runnable- und Callable-Aufgaben und rufen Sie Ergebnisse über Future ab. Du übst Java Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Java Academy zu starten?

Keine Vorkenntnisse erforderlich. Java Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „Aufgaben übermitteln: Runnable vs. Callable“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Java Academy-Lektion Code schreiben und ausführen?

Ja. Jede Java Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. ExecutorService und Thread-Pool-Typen
  2. Aufgaben übermitteln: Runnable vs. Callable
  3. Future und Fehlerbehandlung
  4. ScheduledExecutorService für wiederkehrende Aufgaben
← Zurück zu Java Academy