Nebenläufige Programmierung mit Java
eBook - ePub

Nebenläufige Programmierung mit Java

Konzepte und Programmiermodelle für Multicore-Systeme

  1. 378 Seiten
  2. German
  3. ePUB (handyfreundlich)
  4. Über iOS und Android verfügbar
eBook - ePub

Nebenläufige Programmierung mit Java

Konzepte und Programmiermodelle für Multicore-Systeme

Über dieses Buch

Damit die Performance-Möglichkeiten moderner Multicore-Rechner effizient genutzt werden, muss die Software dafür entsprechend entworfen und entwickelt werden. Für diese Aufgabe bietet insbesondere Java vielfältige Konzepte an. Das Buch bietet eine fundierte Einführung in die nebenläufige Programmierung mit Java. Der Inhalt gliedert sich dabei in fünf Teile: Im ersten Teil wird das grundlegende Thread-Konzept besprochen und die Koordinierung nebenläufiger Programmflüsse durch rudimentäre Synchronisationsmechanismen erläutert. Im zweiten Teil werden weiterführende Konzepte wie Threadpools, Futures, Atomic-Variablen und Locks vorgestellt. Ergänzende Synchronisationsmechanismen zur Koordinierung mehrerer Threads werden im dritten Teil eingeführt. Teil vier bespricht das ForkJoin-Framework, die Parallel Streams und die Klasse CompletableFuture, mit denen auf einfache Art und Weise nebenläufige Programme erstellt werden können. Im fünften Teil findet der Leser Beispiele für die Anwendung der vorgestellten Konzepte und Klassen. Dabei werden auch das Thread-Konzept von JavaFX und Android sowie das Programmiermodell mit Aktoren vorgestellt. Der Anhang enthält einen Ausblick auf Java 9, das bezüglich des Concurrency-API kleine Neuerungen bringt. Alle Codebeispiele stehen auf der Webseite zum Buch zum Download bereit.

Häufig gestellte Fragen

Ja, du kannst dein Abo jederzeit über den Tab Abo in deinen Kontoeinstellungen auf der Perlego-Website kündigen. Dein Abo bleibt bis zum Ende deines aktuellen Abrechnungszeitraums aktiv. Erfahre, wie du dein Abo kündigen kannst.
Nein, Bücher können nicht als externe Dateien, z. B. PDFs, zur Verwendung außerhalb von Perlego heruntergeladen werden. Du kannst jedoch Bücher in der Perlego-App herunterladen, um sie offline auf deinem Smartphone oder Tablet zu lesen. Weitere Informationen hier.
Perlego bietet zwei Abopläne an: Elementar und Erweitert
  • Elementar ist ideal für Lernende und Profis, die sich mit einer Vielzahl von Themen beschäftigen möchten. Erhalte Zugang zur Basic-Bibliothek mit über 800.000 vertrauenswürdigen Titeln und Bestsellern in den Bereichen Wirtschaft, persönliche Weiterentwicklung und Geisteswissenschaften. Enthält unbegrenzte Lesezeit und die Standardstimme für die Funktion „Vorlesen“.
  • Pro: Perfekt für fortgeschrittene Lernende und Forscher, die einen vollständigen, uneingeschränkten Zugang benötigen. Schalte über 1,4 Millionen Bücher zu Hunderten von Themen frei, darunter akademische und hochspezialisierte Titel. Das Pro-Abo umfasst auch erweiterte Funktionen wie Premium-Vorlesen und den Recherche-Assistenten.
Beide Abopläne sind mit monatlichen, halbjährlichen oder jährlichen Abrechnungszyklen verfügbar.
Wir sind ein Online-Abodienst für Lehrbücher, bei dem du für weniger als den Preis eines einzelnen Buches pro Monat Zugang zu einer ganzen Online-Bibliothek erhältst. Mit über 1 Million Büchern zu über 1.000 verschiedenen Themen haben wir bestimmt alles, was du brauchst! Weitere Informationen hier.
Achte auf das Symbol zum Vorlesen bei deinem nächsten Buch, um zu sehen, ob du es dir auch anhören kannst. Bei diesem Tool wird dir Text laut vorgelesen, wobei der Text beim Vorlesen auch grafisch hervorgehoben wird. Du kannst das Vorlesen jederzeit anhalten, beschleunigen und verlangsamen. Weitere Informationen hier.
Ja! Du kannst die Perlego-App sowohl auf iOS- als auch auf Android-Geräten nutzen, damit du jederzeit und überall lesen kannst – sogar offline. Perfekt für den Weg zur Arbeit oder wenn du unterwegs bist.
Bitte beachte, dass wir Geräte, auf denen die Betriebssysteme iOS 13 und Android 7 oder noch ältere Versionen ausgeführt werden, nicht unterstützen können. Mehr über die Verwendung der App erfahren.
Ja, du hast Zugang zu Nebenläufige Programmierung mit Java von Jörg Hettel,Manh Tien Tran im PDF- und/oder ePub-Format sowie zu anderen beliebten Büchern aus Computer Science & Parallel Programming. Aus unserem Katalog stehen dir über 1 Million Bücher zur Verfügung.

1 Einführung

Die meisten Computer können heute verschiedene Anweisungen parallel abarbeiten. Um diese zur Verfügung stehende Ressource auszunutzen, müssen wir sie bei der Softwareentwicklung entsprechend berücksichtigen. Die nebenläufige Programmierung wird deshalb häufiger eingesetzt. Der Umgang und die Koordinierung von Threads gehören heute zum Grundhandwerk eines guten Entwicklers.

1.1 Dimensionen der Parallelität

Bei Softwaresystemen gibt es verschiedene Ebenen, auf denen Parallelisierung eingesetzt werden kann bzw. bereits eingesetzt wird. Grundlegend kann zwischen Parallelität auf der Prozessorebene und der Systemebene unterschieden werden [26, 15]. Auf der Prozessorebene lassen sich die drei Bereiche Pipelining (Fließbandverarbeitung), superskalare Ausführung und Vektorisierung für die Parallelisierung identifizieren.
Auf der Systemebene können je nach Prozessoranordnung und Zugriffsart auf gemeinsam benutzte Daten folgende Varianten unterschieden werden:
  • Bei Multinode-Systemen wird die Aufgabe über verschiedene Rechner hinweg verteilt. Jeder einzelne Knoten (in der Regel ein eigenständiger Rechner) hat seinen eigenen Speicher und Prozessor. Man spricht in diesem Zusammenhang von verteilten Anwendungen.
  • Bei Multiprocessor-Systemen ist die Anwendung auf verschiedene Prozessoren verteilt, die sich in der Regel alle auf demselben Rechner (Mainboard) befinden und die alle auf denselben Hauptspeicher zugreifen, wobei die Zugriffszeiten nicht einheitlich sind. Jeder Prozessor hat darüber hinaus auch noch verschiedene Cache-Levels. Solche Systeme besitzen häufig eine sogenannte NUMA-Architektur (Non-Uniform Memory Access).
  • Bei Multicore-Systemen befinden sich verschiedene Rechenkerne in einem Prozessor, die sich den Hauptspeicher und zum Teil auch Caches teilen. Der Zugriff auf den Hauptspeicher ist von allen Kernen gleich schnell. Man spricht in diesem Zusammenhang von einer UMA-Architektur (Uniform Memory Access).
Neben den hier aufgeführten allgemeinen Unterscheidungsmerkmalen gibt es noch weitere, herstellerspezifische Erweiterungsebenen. Genannt sei hier z. B. das von Intel eingeführte Hyper-Threading. Dabei werden Lücken in der Fließbandverarbeitung mit Befehlen von anderen Prozessen möglichst aufgefüllt.
Hinweis
In dem vorliegenden Buch werden wir uns ausschließlich mit den Konzepten und Programmiermodellen für Multicore- bzw. Multiprocessor-Systeme mit Zugriff auf einen gemeinsam benutzten Hauptspeicher befassen, wobei wir auf die Besonderheiten der NUMA-Architektur nicht eingehen. Bei Java hat man außer der Verwendung der beiden VM-Flags -XX:+UseNUMA und -XX:+UseParallelGC kaum Einfluss auf das Speichermanagement.

1.2 Parallelität und Nebenläufigkeit

Zwei oder mehrere Aktivitäten (Tasks) heißen nebenläufig, wenn sie zeitgleich bearbeitet werden können. Dabei ist es unwichtig, ob zuerst der eine und dann der andere ausgeführt wird, ob sie in umgekehrter Reihenfolge oder gleichzeitig erledigt werden. Sie haben keine kausale Abhängigkeit, d.h., das Ergebnis einer Aktivität hat keine Wirkung auf das Ergebnis einer anderen und umgekehrt. Das Abstraktionskonzept für Nebenläufigkeit ist bei Java der Thread, der einem eigenständigen Kontrollfluss entspricht.
Besitzt ein Rechner mehr als eine CPU bzw. mehrere Rechenkerne, kann die Nebenläufigkeit parallel auf Hardwareebene realisiert werden. Dadurch besteht die Möglichkeit, die Abarbeitung eines Programms zu beschleunigen, wenn der zugehörige Kontrollfluss nebenläufige Tasks (Aktivitäten) beinhaltet. Dabei können moderne Hardware und Übersetzer nur bis zu einem gewissen Grad automatisch ermitteln, ob Anweisungen sequenziell oder parallel (gleichzeitig) ausgeführt werden können. Damit Programme die Möglichkeiten der Multicore-Prozessoren voll ausnutzen können, müssen wir die Parallelität explizit im Code berücksichtigen.
Die nebenläufige bzw. parallele Programmierung beschäftigt sich zum einen mit Techniken, wie ein Programm in einzelne, nebenläufige Abschnitte/Teilaktivitäten zerlegt werden kann, zum anderen mit den verschiedenen Mechanismen, mit denen nebenläufige Abläufe synchronisiert und gesteuert werden können. So schlagen z. B. Mattson et al. in [37] ein »patternbasiertes« Vorgehen für das Design paralleler Anwendungen vor. Ähnliche Wege werden auch in [7] oder [38] aufgezeigt. Spezielle Design-Patterns für die nebenläufige Programmierung findet man in [15, 38, 42, 45].

1.2.1 Die Vorteile von Nebenläufigkeit

Der Einsatz von Nebenläufigkeit ermöglicht die Anwendung verschiedener neuer Programmierkonzepte. Der offensichtlichste Vorteil ist die Steigerung der Performance. Auf Maschinen mit mehreren CPUs kann zum Beispiel das Sortieren eines großen Arrays auf mehrere Threads verteilt werden. Dadurch kann die zur Verfügung stehende Rechenleistung voll ausgenutzt und somit die Leistungsfähigkeit der Anwendung verbessert werden. Ein weiterer Aspekt ist, dass Threads ihre Aktivitäten unterbrechen und wiederaufnehmen können. Durch Auslagerung der blockierenden Tätigkeiten in separate Threads kann die CPU in der Zwischenzeit andere Aufgaben erledigen. Hierdurch ist es möglich, asynchrone Schnittstellen zu implementieren und somit die Anwendung reaktiv zu halten. Dieser Gesichtspunkt gewinnt immer mehr an Bedeutung.

1.2.2 Die Nachteile von Nebenläufigkeit

Der Einsatz von Nebenläufigkeit hat aber nicht nur Vorteile. Er kann unter Umständen sogar mehr Probleme verursachen, als damit gelöst werden. Programmcode mit Multithreading-Konzepten ist nämlich oft schwer zu verstehen und mit hohem Aufwand zu warten. Insbesondere wird das Debugging erschwert, da die CPU-Zuteilung an die Threads nicht deterministisch ist und ein Programm somit jedes Mal verschieden verzahnt abläuft.
Parallel ablaufende Threads müssen koordiniert werden, sodass man immer mehrere Programmflüsse im Auge haben muss, insbesondere wenn sie auf gemeinsame Daten zugreifen. Wenn eine Variable von einem Thread geschrieben wird, während der andere sie liest, kann das dazu führen, dass das System in einen falschen Zustand gerät. Für gemeinsam verwendete Objekte müssen gesondert Synchronisationsmechanismen eingesetzt werden, um konsistente Zustände sicherzustellen. Des Weiteren kommen auch Cache-Effekte hinzu. Laufen zwei Threads auf verschiedenen Kernen, so besitzt jeder seine eigene Sicht auf die Variablenwerte. Man muss nun dafür Sorge tragen, dass gemeinsam benutzte Daten, die aus Performance-Gründen in den Caches gehalten werden, immer synchron bleiben. Weiter ist es möglich, dass sich Threads gegenseitig in ihrem Fortkommen behindern oder sogar verklemmen.

1.2.3 Sicherer Umgang mit Nebenläufigkeit

Den verschiedenen Nachteilen versucht man durch die Einführung von Parallelisierungs- und Synchronisationskonzepten auf höherer Ebene entgegenzuwirken. Ziel ist es, dass Entwickler möglichst wenig mit Low-Level-Synchronisation und Thread-Koordination in Berührung kommen. Hierzu gibt es verschiedene Vorgehensweisen. So wird z. B. bei C/C++ mit OpenMP1 die Steuerung der Parallelität deklarativ über #pragma im Code verankert. Der Compiler erzeugt aufgrund dieser Angaben parallel ablaufenden Code. Die Sprache Cilk erweitert C/C++ um neue Schlüsselworte, wie z. B. cilk_for2.
Java geht hier den Weg über die Bereitstellung einer »Concurrency-Bibliothek«, die mit Java 5 eingeführt wurde und sukzessive erweitert wird. Nachdem zuerst Abstraktions- und Synchronisationskonzepte wie Thread-pools, Locks, Semaphore und Barrieren angeboten wurden, sind mit Java 7 und Java 8 auch Parallelisierungsframeworks hinzugekommen. Nicht vergessen werden darf hier auch die Einführung Thread-sicherer Datenstrukturen, die unverzichtbar bei der Implementierung von Multithreaded-Anwendungen sind...

Inhaltsverzeichnis

  1. Cover
  2. Titel
  3. Impressum
  4. Vorwort
  5. Inhaltsverzeichnis
  6. Kapitel 1: Einführung
  7. Teil I: Grundlegende Konzepte
  8. Teil II: Weiterführende Konzepte
  9. Teil III: Ergänzende Synchronisationsmechanismen
  10. Teil IV: Parallelisierungsframeworks
  11. Teil V: Fallbeispiele
  12. Teil VI: Anhang
  13. Fußnoten