Frage

Check meldet diesen Code als „Die doppelt überprüft Verriegelung Idiom ist gebrochen“, aber ich glaube nicht, dass mein Code tatsächlich durch die Probleme mit doppelt überprüft Verriegelung betroffen ist.

Der Code soll eine Zeile in einer Datenbank erstellen, wenn eine Zeile mit dieser ID existiert nicht. Es läuft in einer Multithreadumgebung und ich möchte die Primärschlüssel-existiert SQL-Ausnahmen vermeiden.

Der Pseudo-Code:

private void createRow(int id) {
  Row row = dao().fetch(id);
  if (row == null) {
     synchronized (TestClass.class) {
        row = dao().fetch(id);
        if (row == null) {
           dao().create(id);
        }
     }
  }
}

kann ich zustimmen, dass es wie doppelt geprüft Verriegelung aussieht, aber ich bin nicht mit statischen Variablen und den Code in fetch () und create () ist wahrscheinlich zu komplex inlined und lösche die Ordnung zu sein.

Bin ich falsch oder check? :)

War es hilfreich?

Lösung

Angenommen, Sie möchten, dass innerste Linie zu lesen:

row = dao().create(id);

Es ist kein klassisches doppelt geprüft Sperre Problem unter der Annahme dao().fetch ordnungsgemäß von der create-Methode mutexed wird.

Bearbeiten : (Code aktualisiert wurde)

Das klassische Problem einen doppelt geprüft Sperre ein Wert zugewiesen wird, nachdem vor der Initialisierung tritt auf, wenn zwei Threads den gleichen Wert zugreifen.

Unter der Annahme, die DAO ordnungsgemäß synchronisiert ist und eine teilweise initialisierten Wert nicht zurück, so leidet nicht an den Fehlern der doppelt überprüft Verriegelung Idiom.

Andere Tipps

Ich denke, in diesem Fall check korrekt ist. In Ihrem Code wie dargestellt, überlegt, was passieren würde, wenn beide zwei Fäden am Eintritt in dem synchronisierten Block row == null haben. Thread A würde geben Sie den Block, und legen Sie die neue Zeile. Dann nach dem Faden A den Block verlässt, Thread B würde den Block eingeben (weil er nicht weiß, was gerade passiert ist), und versuchen Sie es erneut die gleiche neue Zeile einzufügen.

Ich sehe Sie einfach den Code geändert und hinzugefügt in eine ziemlich wichtige fehlende Zeile. In der neue Code, können Sie in der Lage sein, mit dem wegzukommen, da zwei Threads nicht auf Änderungen an einem gemeinsamen (statisch) variabel angewiesen sein. Aber Sie könnten besser dran, zu sehen, ob Ihr DBMS eine Anweisung wie INSERT OR UPDATE unterstützt.

Ein weiterer guter Grund, diese Funktionalität auf das DBMS zu delegieren, wenn Sie jemals mehr als einen Anwendungsserver benötigen bereitstellen. Da synchronized Blöcke, nicht über Maschinen arbeiten werden Sie sowieso etwas anderes in diesem Fall zu tun haben.

Wenn Sie gereizt werden, Code wie diesen zu schreiben, sollten Sie:

  • Seit Java 1.4 hat ziemlich billig geworden Methoden zu synchronisieren. Es ist nicht kostenlos, aber die Laufzeit wirklich nicht so viel leiden, dass es zu Risikodaten Korruption lohnt,.

  • Da Java 1.5, können Sie die Atomic * Klassen haben, die Ihnen erlauben, zu lesen und setzen Felder in einer atomaren Weise. Leider haben sie nicht lösen Ihr Problem. Warum sie nicht AtomicCachedReference oder etwas hinzufügen (die eine überschreibbare Methode nennen würden, wenn get () aufgerufen wird und der aktuelle Wert == null) ist mir schleierhaft.

  • Versuchen Sie ehcache . Es ermöglicht Ihnen, einen Cache einzurichten (das heißt und Objekt, das Sie Code aufrufen können, wenn ein Schlüssel ist nicht in einer Karte enthalten). Dies ist in der Regel, was Sie wollen und die Caches wirklich Ihr Problem lösen (und all die anderen Probleme, die Sie nicht wissen, dass sie noch gar nicht existierte).

Wie andere haben darauf hingewiesen, dieser Code wird tun, was Sie können wie beabsichtigt, sondern nur unter einem strengen Satz von nicht offensichtlichen Annahmen:

  1. Der Java-Code ist nicht gruppiert (siehe @ Greg H Antwort)
  2. Die "Reihe" Referenz nur wird für null in der ersten Zeile überprüft, bevor der Synchronisationsblock.

Der Grund, die doppelt überprüft Verriegelung Idiom gebrochen wird (pro Abschnitt 16.2.4 der Java Concurrency in der Praxis ) ist, dass es dieses Verfahren für einen Faden zu sehen, eine nicht null, aber falsch initialisiert Verweis auf „Reihe“, vor dem Eintritt in den synchronisierten Block (es sei denn „DAO“ liefert korrekte Synchronisation) möglich ist. Wenn Ihre Methode wurde etwas zu tun mit „Reihe“ außer Kontrolle, dass es null ist oder nicht, wäre es gebrochen werden. Wie es aussieht, ist es wahrscheinlich in Ordnung, aber sehr zerbrechlich - ich persönlich würde nicht bequem sein, diesen Code zu begehen, wenn ich dachte, es gab sogar eine entfernte Möglichkeit, dass einige andere Entwickler zu einem späteren Zeitpunkt des Verfahrens ändern könnte ohne zu verstehen, die Feinheiten der DCL.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top