← SEARCHABLE ARCHIVE
Java · 2026-08-08

Java von den Grundlagen bis zum Profi — Folge 8

Threads und asynchrone Vorgänge sicher ausführen

INTERACTIVE READING MODE →

Die in diesem Blog verfassten Artikel wurden mit dem Ziel erstellt, zu unterrichten. Außerdem können die Informationen im Artikel falsch sein, also seien Sie bitte vorsichtig.

Das gleichzeitige Ausführen mehrerer Aufgaben kann den Durchsatz erhöhen, erhöht aber auch die Komplexität des gemeinsamen Status. Bevor Sie sich für die Anzahl der Threads entscheiden, müssen Sie entscheiden, wer den Status ändern wird und wie Abschluss und Fehler kommuniziert werden sollen.

ExecutorService

ExecutorService executor = Executors.newFixedThreadPool(4);

try {
    Future<Integer> result = executor.submit(() -> loadScore());
    int score = result.get();
    System.out.println(score);
} finally {
    executor.shutdown();
}

Wenn eine Aufgabe an ExecutorService übermittelt wird, verwaltet der Executor die Thread-Erstellung und -Wiederverwendung. Futures get lässt den aktuellen Thread warten, bis er abgeschlossen ist, und löst außerdem eine Task-Ausnahme aus.

Gemeinsamen Zustand schützen

private final Object lock = new Object();
private int gold;

public void addGold(int amount) {
    synchronized (lock) {
        gold += amount;
    }
}

Wenn mehrere Threads gleichzeitig denselben Wert lesen und schreiben, können Vorgänge verloren gehen oder Zwischenzustände auftreten. synchronisiert erlaubt nur einem Thread, Abschnitte gleichzeitig auszuführen, die dieselbe Sperre verwenden.

Wenn der Sperrbereich zu groß ist, erhöht sich die Wartezeit, und der Erwerb mehrerer Sperren in unterschiedlicher Reihenfolge kann zu einem Deadlock führen. Wenn möglich, ist es besser, den veränderlichen gemeinsamen Zustand selbst zu reduzieren.

CompletableFuture

CompletableFuture<Player> playerFuture =
    CompletableFuture.supplyAsync(this::loadPlayer, executor);

CompletableFuture<List<Item>> itemFuture =
    CompletableFuture.supplyAsync(this::loadItems, executor);

CompletableFuture<Void> all =
    CompletableFuture.allOf(playerFuture, itemFuture);

all.join();

Sie können zunächst unabhängige Aufgaben starten und die Schritte nach Abschluss kombinieren. Es sollte klar sein, in welchem ​​Executor der Code ausgeführt wird und wo Ausnahmen behandelt werden.

Parallelität macht Ihren Code nicht automatisch schneller. Jobgröße, Latenz, gemeinsam genutzter Status und Executor-Beendigung müssen gemessen und verwaltet werden.