Wie kann ich Getter synchronisieren, während ein Setter in Java arbeitet?

8

Ich habe eine Multi-Thread-Anwendung mit einer einzigen statischen Klasse, die eine Liste bereitstellt. Ich möchte, dass Getter der statischen Klasse frei arbeiten (nicht miteinander synchronisiert werden), aber wenn ein Setter arbeitet, möchte ich, dass alle Getter gesperrt werden und warten, bis die Aufgabe erledigt ist. Ich möchte Getter nicht sperren, wenn sie zusammengerufen werden, da dies die Leistung stark beeinträchtigen würde. Getters werden 1.000.000 Mal pro Tag aufgerufen und Setter soll nur einmal pro Tag arbeiten.

    
Jimmy Page 19.11.2011, 16:37
quelle

4 Antworten

8

Verwenden Sie eine java.util.concurrent.locks.ReadWriteLock -Implementierung, z. B. ReentrantReadWriteLock (siehe Javadoc )

  

A ReadWriteLock unterhält ein Paar zugehöriger Sperren, eine für schreibgeschützte Operationen und eine für schreibende Operationen. Die Lesesperre kann gleichzeitig von mehreren Leser-Threads gehalten werden, solange es keine Writer gibt. Die Schreibsperre ist exklusiv.

Sie würden dies anstelle von synchronized verwenden. Ihre Getter erhalten die Lesesperre und geben sie dann frei, wenn sie zurückkehren, z. B.

%Vor%

Ähnliches für Setter-Methoden, aber stattdessen readWriteLock.writeLock() verwenden.

Die Klasse würde ein einzelnes ReentrantReadWriteLock -Objekt haben, das von allen Getter und Setter für jedes Objekt (oder, falls gewünscht, eines pro Getter / Setter-Paar) geteilt wird.

Es ist ziemlich umständlich, sollte aber gute Nebenläufigkeit geben. Aus diesen Gründen sollten Sie dies nur dann tun, wenn Sie es wirklich brauchen, und das bedeutet, dass Sie die beeinträchtigte Gleichzeitigkeit messen müssen, die Sie erhalten, wenn Sie nur die Vanilla-Synchronisation verwenden.

    
skaffman 19.11.2011, 16:55
quelle
6

Ihr Setter kann bei jedem Update eine Kopie der Daten machen, und Getter können die Kopie verwenden. Dies kann für den Setzer sehr teuer sein, aber nur minimal für die Getter.

Eine synchronisierte Sperre kann jedoch in der Größenordnung von 25 bis 100 ns liegen. Selbst wenn Sie eine synchronisierte Methode eine Million Mal pro Minute aufrufen, fügt synchronized möglicherweise nicht genügend Verzögerung hinzu, um die Sie sich kümmern müssen. Mit einer Million pro Sekunde wird es definitiv.

    
Peter Lawrey 19.11.2011 16:45
quelle
3

Ich würde zuerst alle Zugriffe synchronisieren und nur optimieren, wenn sich das als Leistungsproblem erweist.

Um zu optimieren, können Sie eine CopyOnWriteArrayList oder eine ReadWriteLock verwenden. Es ist schwer, eine endgültige Lösung zu geben, ohne den Kontext genauer zu kennen.

    
JB Nizet 19.11.2011 16:55
quelle
1

Dies ist der archetypische Fall, um eine CopyOnWriteArrayList zu verwenden.

"Dies ist normalerweise zu kostspielig, kann aber effizienter sein als Alternativen, wenn Traversierungsoperationen den Mutationen weit überlegen sind, und ist nützlich, wenn Sie Traversalen nicht synchronisieren können oder wollen, aber Interferenzen zwischen gleichzeitigen Threads ausschließen müssen."

    
user949300 19.11.2011 17:15
quelle

Tags und Links