Parallelität und Multithreading in Java: Fortgeschrittene Techniken

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Parallelität und Multithreading in Java: Fortgeschrittenes Niveau

\n\n

Multithreading in Java ist eines der mächtigsten und gleichzeitig komplexesten Themen. Auf der Anfängerebene verwenden wir synchronized und Thread, aber für den Aufbau leistungsfähiger und skalierbarer Systeme ist ein tieferes Verständnis erforderlich. In diesem Artikel behandeln wir fortgeschrittene Parallelitätsmechanismen: Thread-Pools, ForkJoinPool, asynchrone Programmierung mit CompletableFuture, Feineinstellung von Sperren und Speicherverwaltung. Das Material richtet sich an Entwickler, die bereits mit den Grundlagen des Multithreading vertraut sind.

\n\n

1. Fortgeschrittene Arbeit mit Thread-Pools: ExecutorService und Konfiguration

\n\n

Die Verwendung von ExecutorService ist der Standard in der industriellen Entwicklung. Der Standard-Executors.newFixedThreadPool(10) ist jedoch nicht immer geeignet. Betrachten wir die Feineinstellung von ThreadPoolExecutor.

\n\n
import java.util.concurrent.*;\n\npublic class CustomThreadPool {\n    public static void main(String[] args) {\n        int corePoolSize = 4;\n        int maxPoolSize = 8;\n        long keepAliveTime = 30;\n        TimeUnit unit = TimeUnit.SECONDS;\n        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);\n\n        ThreadPoolExecutor executor = new ThreadPoolExecutor(\n                corePoolSize,\n                maxPoolSize,\n                keepAliveTime,\n                unit,\n                workQueue,\n                new ThreadPoolExecutor.CallerRunsPolicy() // Sättigungsstrategie\n        );\n\n        // Überwachung des Pool-Zustands\n        executor.submit(() -> {\n            System.out.println("Aktive Threads: " + executor.getActiveCount());\n            System.out.println("Abgeschlossene Aufgaben: " + executor.getCompletedTaskCount());\n        });\n\n        executor.shutdown();\n    }\n}
\n\n

Wichtige Parameter:

\n
    \n
  • corePoolSize — minimale Anzahl von Threads, die auch ohne Aufgaben gehalten werden.
  • \n
  • maxPoolSize — maximale Anzahl von Threads.
  • \n
  • keepAliveTime — Lebensdauer überschüssiger Threads.
  • \n
  • workQueue — Aufgabenwarteschlange. ArrayBlockingQueue mit begrenzter Größe verhindert Speicherüberlauf.
  • \n
  • Sättigungsstrategie — was zu tun ist, wenn die Warteschlange voll ist und alle Threads beschäftigt sind. CallerRunsPolicy verlangsamt den aufrufenden Thread.
  • \n
\n\n

Für langlaufende I/O-Aufgaben ist es besser, corePoolSize zu erhöhen, für CPU-gebundene Aufgaben sollte man sich an Runtime.getRuntime().availableProcessors() orientieren.

\n\n

2. ForkJoinPool und rekursive Aufgaben

\n\n

ForkJoinPool ist ein spezialisierter Pool für Aufgaben, die in Teilaufgaben aufgeteilt werden können (Teile und herrsche). Er nutzt effizient Work-Stealing.

\n\n

Beispiel: Rekursive Berechnung der Summe der Elemente eines Arrays.

\n\n
import java.util.concurrent.RecursiveTask;\nimport java.util.concurrent.ForkJoinPool;\n\npublic class SumTask extends RecursiveTask<Long> {\n    private static final int THRESHOLD = 1000;\n    private final int[] array;\n    private final int start;\n    private final int end;\n\n    public SumTask(int[] array, int start, int end) {\n        this.array = array;\n        this.start = start;\n        this.end = end;\n    }\n\n    @Override\n    protected Long compute() {\n        if (end - start <= THRESHOLD) {\n            long sum = 0;\n            for (int i = start; i < end; i++) {\n                sum += array[i];\n            }\n            return sum;\n        }\n        int mid = (start + end) / 2;\n        SumTask leftTask = new SumTask(array, start, mid);\n        SumTask rightTask = new SumTask(array, mid, end);\n\n        leftTask.fork(); // asynchroner Start\n        long rightResult = rightTask.compute(); // berechnen                

Blogs

Buchempfehlungen