Buffer-Vector einzeln und zusammen synchronisieren

mabuhay

Bekanntes Mitglied
Guten Abend

Ich habe eine Frage zur Synchronisation. Ich habe einen Vektor buffers mit mehreren Buffern (LinkedList). Auf diese Buffer wird jeweils aus unterschiedlichen Threads zugegriffen, darum muss ich die natürlich synchronisieren. Ich hab dies nun einfach jeweils so gemacht für das hinzufügen/lesen einzelner Werte aus einzelnen Buffern:

Java:
...

LinkedList<Number> list = buffers.get(bufferIndex);
			
synchronized (list) {
	return list.get(valuePos);
}

...

Somit ist jeweils sichergestellt, das aus einem der Buffer nicht gleichzeitig gelesen und geschrieben wird. (oder?)

Ich habe jetzt aber auch noch eine Methoden, welche alle der Buffer gleichzeitig bearbeitet, also ich kann mit der folgenden Methode zu jedem Buffer "aufs mal" einen Wert hinzufügen. Es gibt dann noch eine Methode getValues() welche aus allen Buffern den ersten wert ausliest.

Java:
public void addValues(Numbers...values) {
LinkedList<Number> list = null;

for (int i = 0; i < buffers.size(); i++) {
	list = buffers.get(i);

	synchronized (list) {
		list.offer(values[i]);
	}
	
}

Wenn ich nun in addValues() nur wie im ersten Codebeispiel jeweils den einen Buffer synchronisiere, könnte es ja sein dass ich gerade bei einem Buffer einen Wert hinzufüge, bei einem anderen aber ein Wert gelesen wird. Ich möchte also, dass ich in den addValues() und getValues() Methoden während dem hinzufügen oder lesen der Werte ALLE der Buffer blocken (synchronisieren) kann.
Möglich wäre es natürlich, wenn ich ein "dummy"-objekt habe auf welches ich zusätzlich noch synchronisiere, dann müsste ich aber um alle schon existierenden synchronized-blöcke noch einen zweiten darum legen.
Java:
Object o = new Object();

...

LinkedList<Number> list = buffers.get(bufferIndex);
synchronized(o) {	
	synchronized (list) {
		return list.get(valuePos);
	}
}

...

Gäbe es da eventuell eine bessere Lösung? oder sogar einen besseren Aufbau?

mfg
 
Zuletzt bearbeitet:
....könnte es ja sein dass ich gerade bei einem Buffer einen Wert hinzufüge, bei einem anderen aber ein Wert gelesen wird.

Sie mag rethorisch wirken, aber ich muss sie stellen: Ist das schlimm? Es entstehen ja keine (intern) inkonsitenten Zustände oder exceptions oder so - jeder Buffer für sich ist "sicher".

Als Alternative, wenn ALLE gelockt werden sollen, würde mir da auch nichts anderes Einfallen, als so ein gemeinsames "Lock"-Objekt (EDIT: Siehe unten) - aber wie der Name schon sagt, würde man da (und eigentlich auch schon beim 'synchronized(list)') auf die Mechanismen aus java.util.concurrent zurückgreifen, siehe Lock Objects (The Java™ Tutorials > Essential Classes > Concurrency) . Da könnte man vielleicht auch noch was trickreiches mit Read/WriteLocks machen, aber dazu müßte man den Anwendungsfall und die Anforderungen genauer kennen...


EDIT: Um das nochmal zu betonen: Dieses verschachtelte synchronized ist halt schon exponentiell häßlicher als ein eizelnes synchronized 😉 Ist "buffers" einfach ein [c]Vector[/c], oder eine eigene Klasse?
 
Zuletzt bearbeitet:
Ja, buffers ist einfach ein Vektor

Ich habe mir vorgestellt es könnte Probleme geben wenn ich zum Beispiel 5 Buffer habe und jeweils einen Wert an einer Position auslese. Jetzt habe ich vielleicht aus den ersten drei Buffern die Werte ausgelesen, der Vierte Buffer wurde aber schon so verändert dass an eben dieser Position gar kein Wert mehr steht. Könnte ich alle Listen synchronisieren, würde das nicht passieren da während dem auslesen der 5 Buffer keiner der Buffer modifiziert werden kann.

Ich habe es nun mal so gelöst, dass wenn beim Auslesen eine Position nicht ausgelesen werden kann, einfach null zurückgegeben wird (anstatt das Array mit jeweils einem Wert von jedem Buffer), oder alternativ dass die Position welche nicht ausgelesen werden kann mit null besetzt wird.

Schon mal danke für deine Antwort. Falls meine Lösung nicht ausreichend ist werde ich mich mal mit dem Link befassen den du gepostet hast.

mfg
 
wenn die Listen/ Buffer so zusammenhängen, dann könntest du überlegen sie gar nicht rauszugeben,
schreibe ne Methode get(bufferIndex, index) in der Hauptverwaltungsklasse, alle Zugriffe über diese Methode,
dann hast du eine zentrale Stelle wo du jederzeit an der Synchronisation feilen kannst,
falls die Methode synchronized ist, ist das ganz sauber ein Ausschluss gegen anderen Zugriff auf die Verwaltung,

aber natürlich schlecht falls irgendwelche Listendurchläufe oder ähnlich kompliziertes auch nötig sind
 

Neue Themen


Zurück
Oben