Programmierung für Schnittstellen und synchronisierte Sammlungen

8

Diese Frage bezieht sich auf Java-Sammlungen - insbesondere auf Hashtable und Vector -, kann sich aber auch anderswo bewerben.

Ich habe an vielen Stellen gelesen, wie gut es ist, Schnittstellen zu programmieren, und ich stimme zu 100% zu. Die Fähigkeit, auf eine List-Schnittstelle zu programmieren, ohne Rücksicht auf die zugrundeliegende Implementierung, ist sicherlich hilfreich für Entkopplungs- und Testzwecke. Mit Sammlungen kann ich sehen, wie eine ArrayList und eine LinkedList unter verschiedenen Umständen anwendbar sind, angesichts der Unterschiede in Bezug auf interne Speicherstruktur, Random Access Times, etc. Diese beiden Implementierungen können jedoch unter der gleichen Schnittstelle verwendet werden ist großartig.

Was ich nicht zu sagen vermag, ist, wie bestimmte synchronisierte Implementierungen (insbesondere Hashtable und Vector) in diese Schnittstellen passen. Für mich scheinen sie nicht zum Modell zu passen. Die meisten zugrunde liegenden Datenstrukturimplementierungen scheinen sich in der Art der Speicherung der Daten zu unterscheiden (LinkedList, Array, sortierter Baum usw.), während die Synchronisation Bedingungen (Sperrbedingungen) betrifft, unter denen auf die Daten zugegriffen werden kann. Sehen wir uns ein Beispiel an, in dem eine Methode eine Map-Sammlung zurückgibt:

%Vor%

Nehmen wir an, dass die Anwendung sich überhaupt nicht mit Nebenläufigkeit beschäftigt. In diesem Fall arbeiten wir mit welcher Implementierung die Methode über die Schnittstelle zurückkehrt ... Jeder ist glücklich. Die Welt ist stabil.

Was ist jedoch, wenn die Anwendung jetzt die Parallelität erfordert? Wir können jetzt nicht ohne Rücksicht auf die zugrunde liegende Implementierung arbeiten - Hashtable wäre in Ordnung, aber andere Implementierungen müssen berücksichtigt werden. Betrachten wir 3 Szenarien:

1) Erzwingen Sie die Synchronisierung mithilfe von Synchronisationsblöcken usw., wenn Sie mit der Sammlung hinzufügen / entfernen. Wäre dies jedoch nicht zuviel für den Fall, dass eine synchronisierte Implementierung (Hashtable) zurückgegeben wird?

2) Ändern Sie die Methodensignatur, um Hashtable zurückzugeben. Dies bindet uns jedoch eng an die Hashtable-Implementierung, und als Ergebnis werden die Vorteile der Programmierung für eine Schnittstelle aus dem Fenster geworfen.

3) Verwenden Sie das Concurrent-Paket, und ändern Sie die Methodensignatur, um eine Implementierung der ConcurrentMap-Schnittstelle zurückzugeben. Das scheint mir der Weg nach vorne zu sein.

Im Wesentlichen scheint es so, als ob bestimmte synchronisierte Implementierungen im Rahmen der Sammlung ein wenig fehl am Platz sind, da bei der Programmierung auf Schnittstellen das Synchronisationsproblem fast dazu zwingt, über die zugrunde liegende Implementierung nachzudenken.

Verpasse ich den Punkt hier völlig?

Danke.

    
user192585 19.10.2009, 21:24
quelle

4 Antworten

6

1) Ja, es wird Overkill sein 2) Richtig, das sollte nicht gemacht werden 3) Hängt von der Situation ab.

Die Sache ist, wie Sie bereits wissen, die Programmierung der Schnittstelle zu beschreiben, was die Anwendung tut (nicht wie es das tut, das ist die Implementierung)

Die Synchronisierung wurde aus nachfolgenden Implementierungen entfernt (erinnern Sie sich, Vector und Hastable sind vor Java 1.2 später kam ArrayList und HasMap, die nicht synchronisiert wurden, aber alle von ihnen implementieren List und Map-Schnittstelle), weil sie zu einer Leistung Strafe fällig zur übermäßigen Synchronisation. Wenn Sie beispielsweise einen Vektor in einem einzelnen Thread verwenden, haben Sie immer noch eine Synchronisation innerhalb dieses einzelnen Threads.

Die gemeinsame Nutzung einer Datenstruktur zwischen mehreren Threads muss beim Entwerfen der Anwendung berücksichtigt werden. Dort werden Sie die Methoden auswählen, die Sie verwenden werden, und Sie werden auswählen, wer dafür verantwortlich ist, den Datenzustand sauber zu halten.

Hier wählen Sie zwischen Option 1 oder 3, die Sie erwähnt haben. Würde es eine manuelle Synchronisation geben? Sollten wir eine synchronisierte Schnittstelle verwenden? Welche Version unterstützen wir usw.?

Wenn Sie z. B. 1 auswählen, können Sie in Ihrem Entwurf auch bestimmte Implementierungen (z. B. Vektoren) ablehnen.

Datensynchronisation ist nicht etwas, das durch "Glück" geschieht, das Sie wirklich entwerfen müssen, damit es richtig geschieht und nicht mehr Probleme verursacht, als diejenigen, die es löst.

Bei diesem Entwurf sollten Sie auf die Optionen (die Implementierungen) und / oder die zugrunde liegende Infrastruktur achten, die Sie verwenden.

Der einfachste Weg, eine übermäßige Synchronisation zu vermeiden, besteht darin, unveränderliche Daten zu verwenden und Ihre Daten nicht mit anderen Threads zu teilen.

Etwas, das dem ersten Gesetz der Verteilung von Computern durch Martin Fowler sehr ähnlich ist:

  

"Daher kommen wir zu meinem ersten Gesetz des verteilten Objektdesigns: Verteilen Sie Ihre Objekte nicht."

Wäre die erste Regel von Multithread-Anwendungen:

  

Erstes Gesetz von Multithread-Anwendungen: Teilen Sie Ihre Daten nicht?

:)

Schlussbemerkung: Die Klasse Sammlungen bietet eine "synchronisierte" Version von einigen Schnittstellen:

Synchronisierte Liste
Synchronized Map
Synchronized Set

    
OscarRyz 19.10.2009, 21:50
quelle
1

Was Sie damit zu tun haben, ist die Tatsache, dass ein Client in einer Multithread-Umgebung nicht naiv ein Objekt verwenden kann, das einen veränderlichen, gemeinsamen Status hat. Die Auflistungsschnittstelle selbst sagt nichts darüber aus, wie das Objekt sicher verwendet werden kann. Wenn Sie eine ConcurrentMap zurückgeben, erhalten Sie zusätzliche Informationen, jedoch nur für diesen speziellen Fall.

Normalerweise müssen Sie die Threadsicherheitsprobleme separat in der Dokumentation (z. B. javadoc) oder mithilfe benutzerdefinierter Annotationen mitteilen, wie in Java Concurrency in Practice. Der Client des zurückgegebenen Objekts muss seinen eigenen oder einen von Ihnen bereitgestellten Sperrmechanismus verwenden. Die Schnittstelle ist normalerweise orthogonal zur Thread-Sicherheit.

Es ist kein Problem, wenn der Client weiß, dass alle Implementierungen aus den Concurrent-Implementierungen stammen, aber diese Informationen nicht von der Schnittstelle selbst kommuniziert werden.

    
David G 19.10.2009 21:49
quelle
0

Javas Vector und Hashtable predigen das aktuelle Concurrency-Paket, das in JDK 5 hinzugefügt wurde. Zu der Zeit, als Vector geschrieben wurde, dachten die Leute, es wäre eine gute Idee, es synchron zu machen, dann würden sie wahrscheinlich die Performancewand treffen im unternehmen verwenden. Nebenläufigkeit ist sicherlich eine der Situationen, in denen Code-zu-Interface-Modularität nicht immer funktioniert.

    
Eugene Yokota 19.10.2009 21:32
quelle
0

Hashtable und Vector sind sehr alt von JDK 1.0. Sie stammen aus JDK1.2 und sollten vor langer Zeit nicht mehr in einem neuen Code verwendet werden. Verwenden Sie HashMap und ArrayList verpackt von Collections.synchronizedMap () oder Collections.synchronizedList () statt.

Sie können die Version sehen, als etwas in das JDK in den API-Dokumenten unter dem Seit-Tag eingeführt wurde.

    
starblue 20.10.2009 06:32
quelle