www.wikidata.de-de.nina.az
Eine doppelt uberprufte Sperrung englisch double checked locking ist ein Muster in der Softwareentwicklung welches dazu dient den Zugriff auf ein gemeinsames Objekt durch mehrere gleichzeitig laufende Threads zu regeln Eine falsch implementierte doppelt uberprufte Sperrung ist ein Antimuster Dies passiert oft unerfahrenen Programmierern die von der Problematik des Lockings wissen aber die falschen Schlusse ziehen Inhaltsverzeichnis 1 Thread sicherer Container 2 Doppelt uberprufte Sperrung in Java 2 1 Losung 3 Doppelt uberprufte Sperrung in C 4 Weblinks 5 EinzelnachweiseThread sicherer Container BearbeitenIm folgenden Beispiel wird ein Element einem Container hinzugefugt oder entfernt Es wird ein Mutex verwendet damit die Funktionen von mehreren Threads nebenlaufig ausgefuhrt werden konnen class Thread sicherer Container container mutex hinzufugen element mutex sperren container hinzufugen element mutex entsperren entfernen element mutex sperren if container ist leer element container entfernen mutex entsperren return element Der Mutex muss in jedem durchgang von entfernen gesperrt werden Um das zu umgehen kann eine doppelt uberprufte Sperrung verwendet werden class Thread sicherer Container container mutex leer hinzufugen element mutex sperren container hinzufugen element leer synchronisiertes speichern false mutex entsperren entfernen element if leer synchronisiertes laden erste Prufung mutex sperren if leer zweite Prufung element container entfernen leer synchronisiertes speichern container ist leer mutex entsperren return element Falls der Container leer ist muss nur eine Variable synchronisiert gelesen werden Dies ist schneller als ein Mutex zu sperren Die erste Prufung muss synchronisiert sein da der Computer ansonsten annehmen kann dass kein anderer Thread leer verandert und er einen teilweise geschriebener Wert ladt Bei der zweiten Prufung stellt der Mutex die Synchronisation sicher Doppelt uberprufte Sperrung in Java BearbeitenObwohl mit Java 5 unter einer neuen Semantik des Schlusselwortes volatile eine doppelt uberprufte Sperrung threadsicher realisiert werden kann gilt es immer noch als Anti Pattern da es zu umstandlich und ineffizient ist Zudem ist der Effizienznachteil von volatile kaum kleiner als von synchronized BeispielDas folgende Beispiel zeigt die Problematik in der getHelper Methode in der fur jedes Foo Objekt genau ein Helper Objekt beim ersten Zugriff erzeugt werden soll public class Foo private Helper helper null public Helper getHelper if helper null erste Prufung synchronized this if helper null zweite Prufung helper new Helper return helper Die Schnittstelle Helper wird genutzt um ausserhalb eines Foo Objektes auf dem Helper Objekt arbeiten zu konnen Definiert man wie hier helper nicht als volatile ist die doppelte Prufung problematisch weil z B ein Java JIT Compiler den Assemblercode so umsortieren kann dass der Verweis auf das Helper Objekt gesetzt wird bevor der Konstruktor vom Helper Objekt vollstandig durchlaufen wurde In diesem Fall liefert getHelper ein nicht initialisiertes Objekt zuruck Losung Bearbeiten Ab Java 5 werden volatile definierte Variablen erst nach vollstandiger Abarbeitung des Konstruktors sichtbar Wird also die Variable helper als volatile definiert lauft obiges Beispiel korrekt durch Falls wie bei der Implementierung eines Singletons nur eine einzige Instanz pro Klasse existieren soll gibt es eine leicht zu implementierende Losung Das Attribut wird als static deklariert und die Erzeugung des Objekts in eine Unterklasse hier nested class ausgegliedert das sog initialization on demand holder Idiom public class Foo private static class HelperHolder public static Helper helper new Helper public Helper getHelper return HelperHolder helper Hierbei wird das statische Attribut der Klasse HelperHolder erst beim Aufruf durch getHelper instanziert 1 also lazy und die Virtuelle Maschine sorgt fur die Threadsicherheit 2 Doppelt uberprufte Sperrung in C BearbeitenAnalog zu Java existiert die doppelt geprufte Sperrung auch in C class Singleton private Singleton private static Singleton instance public static Singleton Instance get if instance null lock lock if instance null instance new Singleton return instance Hilfsfeld fur eine sichere Threadsynchronisierung private static readonly object lock new object Soll kein dezidiertes Hilfsfeld genutzt werden kann wie in Java auf this gelockt werden Dies gilt jedoch als bad practice 3 da hierdurch leicht sog Deadlocks entstehen konnen Ein dezidiertes Lock Objekt ist in so gut wie jedem Falle vorzuziehen class Singleton private Singleton private static Singleton instance public static Singleton Instance get if instance null lock this if instance null instance new Singleton return instance Eine weitere Moglichkeit besteht darin die Singleton Variable direkt in der Felddeklaration zu initialisieren Dadurch ist die uberprufte Sperrung uberflussig jedoch ist die Initialisierung dann nicht mehr lazy bzw wird beim ersten Zugriff auf die Klasse durchgefuhrt Threadsicherheit wird durch die CLR gewahrt class Singleton private Singleton private static readonly Singleton instance new Singleton public static Singleton Instance get return instance Die beste Moglichkeit ab NET 4 0 ist der Einsatz der Lazy lt T gt Klasse 4 welche intern eine korrekte Form der doppelt uberpruften Sperrung verwendet 5 Weblinks BearbeitenWeiterfuhrende Erklarung des Themas mit Assembler Beispiel englisch Einzelnachweise Bearbeiten Java Language Specification Java SE 7 Edition 12 4 1 Java Language Specification Java SE 7 Edition 12 4 2 lock Statement C Reference In MSDN Microsoft abgerufen am 17 Oktober 2014 englisch Lazy lt T gt Class In MSDN Microsoft abgerufen am 27 Juli 2014 englisch Ben Watson Writing High Performance NET Code 2014 ISBN 978 0 9905834 3 1 englisch Abgerufen von https de wikipedia org w index php title Doppelt uberprufte Sperrung amp oldid 228858140