2009-03-20 4 views
4

In meiner Anwendung habe ich eine Schlüssel-Wert-Karte, die als zentrales Repository zum Speichern von Daten dient, die verwendet wird, um nach einem Absturz oder Neustart (Checkpointing) in einen definierten Zustand zurückzukehren.Wie kann ich einen threadsafe Point-in-Time-Snapshot einer Schlüssel-Wert-Map in Java durchführen?

Die Anwendung ist Multithread und mehrere Threads können Schlüssel-Wert-Paare in diese Zuordnung einfügen. Ein Thread ist verantwortlich für das regelmäßige Erstellen eines Checkpoints, d. e. Serialisieren Sie die Karte in den persistenten Speicher.

Während der Prüfpunkt geschrieben wird, sollte die Karte unverändert bleiben. Es ist ziemlich einfach zu vermeiden, dass neue Elemente hinzugefügt werden, aber was ist mit anderen Threads, die Mitglieder von "ihren" Objekten in der Karte ändern?

Ich könnte ein einzelnes Objekt haben, dessen Monitor erfasst wird, wenn der Checkpointing beginnt, und den gesamten Schreibzugriff auf ein Mitglied der Map und deren Mitglieder in Blöcken umwandeln, die auf diesem Objekt synchronisieren. Dies scheint mir sehr fehleranfällig und langwierig zu sein.

Ich könnte auch die Karte privat zum Checkpointer machen und nur Kopien der eingereichten Objekte hineinlegen. Aber dann müsste ich sicherstellen, dass die Kopien tiefe Kopien sind und ich nicht in der Lage wäre, die Daten in der Karte automatisch zu aktualisieren, bei jeder Änderung an den übermittelten Objekten müssten die Übermittler sie erneut einreichen. Dies scheint eine Menge Overhead zu sein und auch fehleranfällig zu sein, da ich mich daran erinnern muss, den Code an den richtigen Stellen erneut zu senden.

Was ist eine elegante und zuverlässige Lösung?

Antwort

1

pgras hat Recht, dass Unveränderlichkeit Dinge reparieren würde, aber das wäre auch schwierig. Sie könnten die ganze Sache einfach abschließen, aber das könnte ein Leistungsproblem sein. Ich kann mir zwei gute Ideen vorstellen.

Zuerst ist eine ReadWriteLock zu verwenden (die 1.5 oder neuer erfordert). Da Ihr Kontrollpunkt die Lesesperre erhalten kann, kann es sicher sein, dass Dinge sicher sind, aber wenn niemand liest, sollte die Leistung ziemlich gut sein. Dies ist immer noch ein ziemlich grobes Schloss, so dass Sie auch wollen, # 2 zu tun ...

Zweitens ist die Dinge zu brechen. Jeder Bereich des Programms könnte seine eigene Karte behalten (die Karte für GUI-Sachen, die Karte für Benutzereinstellungen, die Karte für Hardware-Einstellungen, was auch immer). Jeder hätte ein Schloss daran und die Dinge liefen wie üblich. Wenn es Zeit für den Checkpoint wurde, würde der Checkpointer ALLE Schlösser (also die Dinge sind konsistent) ergreifen und dann seinen Job machen. Der Haken hier ist, dass Sie eine Reihenfolge für die zu greifenden Sperren definiert haben (alphabetisch), sonst werden Sie mit Deadlocks enden.

Wenn die Karten orthogonal zueinander sind (Updates für eins erfordern keine Aktualisierungen für ein anderes, um konsistent zu sein), dann ist es am einfachsten, die Updates ähnlich wie beim Checkpointer auf eine zentrale "Backup" -Karte zu schieben etwas, das du beschrieben hast.

Meine größte Frage an Sie wäre, wie viel von einem Problem ist dies (Leistung)? Sind Updates sehr häufig oder sind sie selten? Das würde helfen, über etwas zu beraten, da meine letzte Idee (vorheriger Abschnitt) langsam sein könnte, aber es ist einfach und macht vielleicht nichts aus.

Es gibt ein fantastisches Buch namens Java Concurrency in Practice, das im Grunde die Java-Threading-Bibel ist. Es beschreibt, wie man diese Art von Dingen und Strategien erkennt, um Probleme zu vermeiden oder sie einfacher zu lösen. Wenn Sie mehr Threading durchführen möchten, ist das ein sehr nützlicher Lesevorgang.

Eigentlich, wenn Ihre Schlüsselwerte orthogonal zueinander sind, dann sind die Dinge wirklich einfach. Die ConcurrentMap Schnittstelle (es gibt Implementierungen wie die ConcurrentHashMap) würde Ihre Probleme lösen, da sie Änderungen atomar machen können, so dass die Leser keine inkonsistenten Daten sehen würden. Aber wenn Sie zwei (oder mehr) Schlüssel haben, die gleichzeitig aktualisiert werden müssen, wird Sie das nicht abdecken.

Ich hoffe, das hilft. Threading-Zugriff auf gemeinsame Datenstrukturen ist komplex.

2

was ist mit anderen Themen Mitglieder „ihre“ Objekte in der Karte

Hier haben Sie ein Problem zu ändern :) und es kann nicht durch irgendeine Art von Karte ...

gelöst werden Eine Lösung wäre, nur unveränderliche Objekte in Ihrer Map zuzulassen, aber dies ist für Sie möglicherweise nicht möglich.

Andernfalls müssen Sie eine Sperre für alle Threads freigeben, die möglicherweise die von Ihrer Map referenzierten Daten ändern und sie während des Snapshots blockieren. aber das ist ein Halt der Weltansatz ...

+0

+1 unveränderliche Objekte, die Karte ist Snapshot des Zustands. Erarbeiten Sie Ihre Klon/Serialisierung und denken Sie daran, über das vorübergehende Schlüsselwort zu lesen – basszero