Modul 16 · Migration Deep Dive · Stufe 2 Java Core

Concurrency

plattformgebundener Thread Pool wird nachvollziehbar in Virtual Threads und sichere Aggregation überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.

Task ExecutorMemoizer
1 → 1Produktionsdateien
24 → 22Java-Zeilen
1 → 1Testdateien
0 / 0Dependencies entfernt / neu
NIEDRIGRisiko · Score 0

Was sich konkret ändert

DimensionLegacyModernMigrationskonsequenz
Programmiermodellimperativ / ohne Framework-Annotationenexplizite Java-AbstraktionenAnnotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen.
Abhängigkeiten1 direkte Dependencies1 direkte Dependencies0 neu, 0 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen.
Öffentliche API1 erkannte Methoden1 erkannte MethodenMethoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag.
Datenmodellclass LegacyTaskRunnerclass VirtualThreadTaskRunnerFeldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet.
FehlerverhaltenLegacy-Exceptions und Rückgabewerteexplizitere Fach-/Framework-FehlerabbildungFehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden.
TestsBestands- und Golden-Master-TestsUnit-, Slice-, Contract- und IntegrationstestsDer Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt.
BetriebLegacy-Start/Lifecyclemodernes Packaging, Health und externe KonfigurationUmstellung über kleine Adapter und Golden-Master-Tests statt Big Bang.
RollbackLegacy-Artefakt bleibt unverändertModern-Artefakt getrennt deploybarKein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein.

Fachlicher Vertrag: unverändert zu erhalten

  • Task-Ergebnisse, Timeout- und Abbruchsemantik sind definiert.
  • Executors/Threads werden zuverlässig geschlossen.
  • Fehler eines Tasks gehen nicht verloren.

Hauptrisiko und Testfokus

race conditions, leaks and nondeterministic tests

timeouts, cancellation, interruption and repeated stress tests

Die Modernisierung gilt erst als abgeschlossen, wenn der fachliche Vertrag automatisiert belegt ist.

Verbindliches Code- und Rollenmapping

Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.

Legacy-Rolle / DateiModern-Rolle / DateiBedeutung
LegacyTaskRunner.javaVirtualThreadTaskRunner.javaFester Pool wird für blockierende Tasks durch Virtual Threads ersetzt.

Legacy-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
LegacyTaskRunner.javaclass LegacyTaskRunnerList<String> run(List<Callable<String>> tasks)Task Executor24

Modern-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
VirtualThreadTaskRunner.javaclass VirtualThreadTaskRunnerList<String> run(List<Callable<String>> tasks)Task Executor22

Dependency- und Laufzeitmigration

StatusDependencyVersionScopePrüfung
BEIBEHALTENorg.junit.jupiter:junit-jupiterBOM/Parent → BOM/Parenttest → testGemeinsame Dependency; Version und Scope im effektiven POM prüfen.
Direkte POM-Daten ersetzen keinen erfolgreichen Online-Build mit transitiver SBOM- und CVE-Prüfung.

Vorher-/Nachher-Codebelege

Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.

Legacy
LegacyTaskRunner.java
Modern
VirtualThreadTaskRunner.java

Migrationsbedeutung: Fester Pool wird für blockierende Tasks durch Virtual Threads ersetzt.

Legacy-Code

projects/16-concurrency/legacy/src/main/java/at/aydin/lab/concurrency/legacy/LegacyTaskRunner.java

package at.aydin.lab.concurrency.legacy;

import java.util.*;
import java.util.concurrent.*;

// Design Pattern: Task Executor
// Zweck: Begrenzter Plattform-Thread-Pool führt blockierende Aufgaben aus.
public final class LegacyTaskRunner {
    public List<String> run(List<Callable<String>> tasks) {
        ExecutorService pool = Executors.newFixedThreadPool(4);
        try {
            List<String> result = new ArrayList<>();
            for (Future<String> f : pool.invokeAll(tasks)) result.add(f.get());
            return result;
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException(ex);
        } catch (ExecutionException ex) {
            throw new IllegalStateException(ex.getCause());
        } finally {
            pool.shutdown();
        }
    }
}

Modern-Code

projects/16-concurrency/modern/src/main/java/at/aydin/lab/concurrency/modern/VirtualThreadTaskRunner.java

package at.aydin.lab.concurrency.modern;

import java.util.*;
import java.util.concurrent.*;

// Design Pattern: Task Executor
// Zweck: Ein Virtual Thread pro blockierender Aufgabe vereinfacht skalierbare Nebenläufigkeit.
public final class VirtualThreadTaskRunner {
    public List<String> run(List<Callable<String>> tasks) {
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            List<Future<String>> futures = tasks.stream().map(executor::submit).toList();
            List<String> result = new ArrayList<>(futures.size());
            for (Future<String> future : futures) result.add(future.get());
            return List.copyOf(result);
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException(ex);
        } catch (ExecutionException ex) {
            throw new IllegalStateException(ex.getCause());
        }
    }
}
Technischen Unified Diff öffnen
--- LegacyTaskRunner.java
+++ VirtualThreadTaskRunner.java
@@ -1,24 +1,22 @@
-package at.aydin.lab.concurrency.legacy;
+package at.aydin.lab.concurrency.modern;
 
 import java.util.*;
 import java.util.concurrent.*;
 
 // Design Pattern: Task Executor
-// Zweck: Begrenzter Plattform-Thread-Pool führt blockierende Aufgaben aus.
-public final class LegacyTaskRunner {
+// Zweck: Ein Virtual Thread pro blockierender Aufgabe vereinfacht skalierbare Nebenläufigkeit.
+public final class VirtualThreadTaskRunner {
     public List<String> run(List<Callable<String>> tasks) {
-        ExecutorService pool = Executors.newFixedThreadPool(4);
-        try {
-            List<String> result = new ArrayList<>();
-            for (Future<String> f : pool.invokeAll(tasks)) result.add(f.get());
-            return result;
+        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
+            List<Future<String>> futures = tasks.stream().map(executor::submit).toList();
+            List<String> result = new ArrayList<>(futures.size());
+            for (Future<String> future : futures) result.add(future.get());
+            return List.copyOf(result);
         } catch (InterruptedException ex) {
             Thread.currentThread().interrupt();
             throw new IllegalStateException(ex);
         } catch (ExecutionException ex) {
             throw new IllegalStateException(ex.getCause());
-        } finally {
-            pool.shutdown();
         }
     }
 }

Umsetzungsplan mit Qualitäts-Gates

  1. Arbeitspaket 1
    Thread-Pool-Größe, Queueing und Blocking-Aufgaben inventarisieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  2. Arbeitspaket 2
    Task-Vertrag und Ergebnisreihenfolge festlegen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  3. Arbeitspaket 3
    VirtualThreadTaskRunner für blockierende unabhängige Tasks einführen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  4. Arbeitspaket 4
    Timeout, Cancellation und InterruptedException korrekt propagieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  5. Arbeitspaket 5
    Last-, Leak- und wiederholte Stress-Tests ausführen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  6. Arbeitspaket 6
    Plattformthread-Pool erst nach Ressourcenmessung entfernen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.

Konkreter Test- und Abnahmekatalog

IDEbenePrüfungerforderlicher Nachweis
16-CONCURRENCY-A01Integration/ContractKein Thread-/Executor-Leak nach wiederholten Läufen.Automatisierter Test und CI-Protokoll
16-CONCURRENCY-A02Integration/ContractTimeout beendet offene Tasks nach Regel.Automatisierter Test und CI-Protokoll
16-CONCURRENCY-A03Integration/ContractUnterbrechung wird nicht verschluckt.Automatisierter Test und CI-Protokoll
16-CONCURRENCY-A04Integration/ContractErgebnisse sind vollständig und korrekt zugeordnet.Automatisierter Test und CI-Protokoll
16-CONCURRENCY-A05Integration/ContractLasttest zeigt keine unkontrollierte externe Ressourcenüberlastung.Automatisierter Test und CI-Protokoll
16-CONCURRENCY-T01UnitFachlogik ohne Container oder externen Dienst testen.Unit-Test
16-CONCURRENCY-T02RegressionLegacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen.Vergleichsreport
16-CONCURRENCY-T03NegativeFehlerhafte, leere und grenzwertige Eingaben prüfen.Negativtest
16-CONCURRENCY-T04OperationsStart, Health, Shutdown und Konfigurationsfehler prüfen.Deployment-/Startprotokoll
16-CONCURRENCY-F01Fokustimeouts, cancellation, interruption and repeated stress testsModulspezifischer Testreport

Risikoregister des Moduls

RisikoAuswirkungGegenmaßnahmeGate
race conditions, leaks and nondeterministic testsNIEDRIGtimeouts, cancellation, interruption and repeated stress testsvor Cutover

Konfiguration und Ressourcen

Keine zusätzlichen Ressourcen.

Rollback und Koexistenz

Der TaskRunner-Vertrag erlaubt Rückschaltung auf den bisherigen Executor; gemeinsam genutzter Zustand muss in beiden Varianten gleich geschützt sein.

Abbruchkriterien

  • Fachlicher Golden-Master weicht ab.
  • Daten-, Nachrichten- oder API-Kompatibilität ist ungeklärt.
  • Fehlerquote, Latenz oder Ressourcenverbrauch überschreiten das vereinbarte Limit.
  • Monitoring oder Rückfallpfad ist nicht funktionsfähig.

Definition of Done

Direkte Arbeitslinks

⌂ Cockpit