2009-05-19 4 views
4

Ich frage mich, ob es möglich ist, das verlorene Update-Problem zu vermeiden, bei dem mehrere Threads dasselbe Datum aktualisieren, während die Verwendung von synchronized(x) { } vermieden wird.Vermeidung eines verlorenen Updates in Java ohne direkte Verwendung der Synchronisation

Ich werde zahlreiche tun fügt und Schritten:

val++; 
ary[x] += y; 
ary[z]++; 

Ich weiß nicht, wie Java, diese in Bytecode kompiliert und wenn ein Thread in der Mitte eines dieser Aussagen Blöcke Byte unterbrochen werden könnte, Code. Mit anderen Worten, sind diese Aussagen sicher?

Auch ich weiß, dass die Vector-Klasse synchronisiert ist, aber ich bin mir nicht sicher, was das bedeutet. Wird der folgende Code threadsicher sein, so ändert sich der Wert an Position i nicht zwischen vec.get(i) und vec.set(...).

class myClass { 
    Vector<Integer> vec = new Vector<>(Integer); 

    public void someMethod() { 
    for (int i=0; i < vec.size(); i++) 
     vec.set(i, vec.get(i) + value); 
    } 
} 

Vielen Dank im Voraus.

Antwort

6

Für die Zwecke des Einfädelns, +++= und werden als zwei Operationen (vier für double und long) behandelt. Updates können sich also gegenseitig stören. Seien Sie nicht nur einer, sondern ein Scheduler, der im falschen Moment agiert, könnte Millisekunden von Updates löschen.

java.util.concurrent.atomic ist dein Freund.

Ihr Code kann sicher gemacht werden, Sie unter der Annahme, nichts dagegen haben, jedes Element einzeln zu aktualisieren und Sie nicht die Größe ändern, wie (!):

for (int i=0; i < vec.size(); i++) { 
    synchronized (vec) { 
     vec.set(i, vec.get(i) + value); 
    } 
} 

Wenn Sie das Ändern der Größe hinzufügen möchten Vector müssen Sie die synchronized Anweisung außerhalb der for Schleife verschieben, und Sie können auch nur einfach neue ArrayList verwenden. Es gibt nicht viel Gebrauch für eine synchronisierte Liste.

Aber man konnte AtomicIntegerArray verwenden:

private final AtomicIntegerArray ints = new AtomicIntegerArray(KNOWN_SIZE); 
[...] 
    int len = ints.length(); 
    for (int i=0; i<len; ++i) { 
     ints.addAndGet(i, value); 
    } 
} 

, die den Vorteil keine Schlösser hat und keine Boxen (!). Die Implementierung ist auch ziemlich spaßig, und Sie müssten es komplizierter aktualisieren (zum Beispiel Zufallszahlengeneratoren).

+0

Ich hatte keine Ahnung java.util.concurrent.atomic existierte, danke! – nash

+0

Es ist ein bisschen auf der Low-Level-Seite. java.util.concurrent ist auf einer allgemein nützlicheren Ebene. –

1

vec.set() und vec.get() sind threadsicher darin, dass sie Werte nicht so setzen und abrufen, dass sie Sätze verlieren und in andere Threads gelangen. Es tut nicht bedeutet, dass Ihr Set und Ihr erhalten ohne Unterbrechung passieren wird.

Wenn Sie wirklich wie in den obigen Beispielen Code schreiben werden, sollten Sie wahrscheinlich etwas sperren. Und synchronized(vec) { } ist so gut wie jeder andere. Sie fragen hier nach zwei Operationen, um synchron zu passieren, nicht nur eine Thread-sichere Operation.

Sogar java.util.concurrent.atomic wird nur sicherstellen, dass eine Operation (get oder set) sicher passiert. Sie müssen in einer Operation erhalten und erhöht werden.

+0

Anders als mit getAndIncrement und ähnlichem?(Technisch implementiert als mehrere Operationen, aber in einer Schleife, falls es scheitert.) –

Verwandte Themen