Was ist neu in Java 7? Teil 3 – Allgemeingültigkeit

Seite 3: Classloading

Inhaltsverzeichnis

Ähnlich tief in der Laufzeit vergraben versteckt sich die nächste Änderung, die JRE 7 mitbringt. Bereits seit dem JDK 1.3 wird eine Änderung des Classloading-Verhaltens gewünscht. Classloader müssen dem Delegationsprinzip folgen und zuerst ihren Vater-Classloader aufrufen. Wird via eigenem Classloader eingegriffen, kann es bei dem Vorgehen zu einem Deadlock kommen, da die relevante Klasse java.lang.ClassLoader.loadClassInternal(String name) "private synchronized" ist und sich somit weder geeignet überschreiben noch mit einem eigenen Synchronisationsmechanismus versehen lässt. Es ist eine Änderung im Classloader durchzuführen, die das parallele Laden mehrerer Klassen ohne Deadlock ermöglicht. Dazu hat Oracle neben dem internen Sperrmechanismus des Classloader auch die Granularität der Sperren angepasst. In der API sind damit zwei neue Methoden entstanden:

java.lang.ClassLoader.registerAsParallelCapable()
java.lang.ClassLoader.getClassLoadingLock(String className)

Classloader, die das gleichzeitige Laden von Klassen ermöglichen und nicht strikt hierarchisch sind, heißen jetzt "parallel capable" und müssen sich während der Initialisierung mit registerAsParallelCapable() anmelden. Das ist auch der Standardfall für alle seine Oberklassen mit Ausnahme von java.lang.Object. Die Registrierung lässt sich nachträglich nicht rückgängig machen.

Von ähnlicher Qualität sind auch die Änderungen am URLClassLoader. Diese Klasse ermöglicht das Erstellen der Classloader von definierten Ressourcen (Verzeichnissen, Dateien etc.). Sollten diese in der Vergangenheit angepasst werden, waren alle Referenzen auf das Objekt zu löschen, und man musste auf den Garbage Collector (GC) warten. Vorher ließen sich die Ressourcen nicht löschen. Da das GC-Verhalten von Java nicht vorhersagbar ist, entstanden zunehmend Probleme. Vornehmlich unter Windows werden Ressourcen nämlich erst gelöscht, wenn keine Referenzen mehr von einem Programm gehalten werden. Für den Fall steht jetzt die close()-Methode zur Verfügung. Sie invalidiert den Classloader und alle daran gebundenen Ressourcen.

        URL url = new URL("file:heise.jar");
URLClassLoader loader = new URLClassLoader(new URL[]{url});
Class cl = Class.forName("Developer", true, loader);
Runnable developer = (Runnable) cl.newInstance();
developer.run();
loader.close();

Die in diesem Artikel beschriebenen Funktionen stellen sicherlich tiefgreifende Änderungen an der Java-Spezifikation dar. Seit Java 1.0 wurde erstmalig neuer Bytecode eingeführt, und auch die Erweiterungen am Classloader sind vergleichbar wichtige Änderungen. Dennoch wurde anscheinend eine vollständige Abwärtskompatibilität bewahrt. Für Java ein Qualitätsmerkmal, das auch in großem Umfang zum Erfolg der vergangenen Jahre beigetragen hat. Leider bleibt für die tägliche Arbeit der Entwickler nicht viel übrig von diesen Anpassungen.

Die für InvokeDynamic hinzugekommene API lässt sich in Java nur bedingt einsetzen und steht dem Entwickler nur indirekt durch weitere Frameworks (etwa ASM) zur Verfügung. Die Veränderungen am Classloader-Verhalten dürfen auch nur einen geringen Prozentsatz an Entwicklern betreffen. Dennoch sind gerade die hier vorgestellten Weiterentwicklungen die Grundlage für die Weiterentwicklung von Java.

Markus Eisele
ist Principle IT Architect bei der msg systems AG in München.
(ane)