Vadym Kazulkin ip.labs GmbH

Entgegen der Erwartung wird das JDK 9 kein Upgrade des Memory Models bekommen.

Rodion Alukhanov ip.labs GmbH

Mit jcstress wird dem Java-Entwickler endlich ein mächtiges Tool zum Testen und Analysieren der Memory- und Concurrency-Probleme zur Seite gestellt.

Das Java Memory Model (JMM) ist schon zwölf Jahre alt. Viele Konzepte und Vorgehensweisen sind nicht mehr ausreichend gedeckt. Es ist Zeit, einen kritischen Blick darauf zu werfen.

Das letzte Update erfolgte mit der Einführung von Java 5 in Form des JSR 133, wo unter anderem das Verhalten von volatile-Variablen vollständig formal beschrieben wurde. Zum Zeitpunkt der Veröffentlichung des JSR 133 existierte Java schon sein mehr als zehn Jahren. Eine der wichtigsten Aufgaben bestand also darin, die Kompatibilität mit dem bestehenden Code zu gewährleisten. Im Laufe der Zeit hat sich eine Reihe von Baustellen geöffnet, die eine Erweiterung des JMM in Aussicht stellt. Die wichtigsten Beweggründe wurden im Rahmen des JEP 188: Java Memory Model Update beschrieben:

  • Formalisierung der Spezifikation
  • Spezifizieren von später dazugekommenen und über API verfügbaren Operationen wie weakCompareAndSet
  • Kompatibilität mit später veröffentlichtem Memory Model von C++ 11 – vor allem in Bezug auf native Aufrufe
  • Testing- und Tooling-Support

Nach dem heutigen Stand im Mai 2017 wird im Rahmen des JDK 9 im Sommer keine formale Neuausrichtung des JMM erfolgen. Nichtsdestotrotz wurden viele der angestrebten Ziele des JEP 188 ganz oder zum Teil in Form von Tooling und API-Erweiterungen erreicht.

Artikelserie

  • Teil 1: Hardware-Memory-Modelle reloaded
  • Teil 2: Problemkategorien im Java Memory Model
  • Teil 3: Das Open JDK Java Concurrency Stress Tests Tool
  • Teil 4: Die Zukunft des Java Memory Model

Atomic-64-Bit-Operationen

Die meiste Hardware unterstützt 64-Bit-atomare Operationen. Dazu zählen auch viele 32-Bit-Architekturen. Die von der Java-Syntax verlangten Zusicherungen in Form von volatile sind dadurch wesentlich aufwendiger und langsamer, als es für die darunterliegende Architektur notwendig wäre. Je nach Hardware ist die eingebaute atomare 64-Bit-Zuweisung zwischen zweimal (ARM7, 32 Bit) und zehnmal (x86, 64 Bit) schneller als volatile. Die Java-Syntax bietet keine andere Möglichkeit für den atomaren 64-Bit-Zugriff, als die Instanzvariable als volatile zu deklarieren. Es gibt Wege, wie man von der Hardwareunterstützung direkt profitieren kann. Einer davon wäre Oracles native, nicht dokumentierte Klasse sun.misc.Unsafe. Seit JDK 6 existiert auch eine legale Möglichkeit. Die Klasse AtomicLong, die eine Alternative zu volatile ist, bietet die Methode lazySet. Das gilt natürlich auch für die anderen atomic-Klassen, wie AtomicInteger oder AtomicReference. Man muss hier explizit erwähnen, dass, obwohl die Methode lazySet ein Bestandteil des API ist, sie sehr sparsam dokumentiert ist. Die Methodenbeschreibung ist nicht an die Spezifikation angelehnt, und die genaue Arbeitsweise, z. B. in Bezug auf Memory-Barrieren, bleibt dem JVM-Anbieter überlassen. Es lässt viel Spielraum und kann je nach JVM-Release anders funktionieren. Moderne Hardware bietet auch andere performanceoptimierende Tricks. Einer davon ist weakCompareAndSet. Als Preis für die bessere Performance kann diese Methode fälschlicherweise false zurückgeben. Diese (wie auch andere lazy-Methoden) ist mit Vorsicht zu genießen und ausführlich zu testen. Sie ist nicht formal durch die Spezifikation abgedeckt und sehr sparsam beschrieben. Es wäre dadurch zu erwarten, dass das Verhalten je nach Hardware und JVM-Anbieter unterschiedlich sein kann. Es erscheint sinnvoll, wenn diese Gruppe von Methoden in einer der nächsten JMM-Spezifikationen ihren Platz findet.

Den vollständigen Artikel lesen Sie in der Ausgabe:

Java Magazin 8.17 - "Agile und DevOps"

Alle Infos zum Heft
579804071Das Java Memory Model auf dem Prüfstand
X
- Gib Deinen Standort ein -
- or -