2015-01-27 13 views
6

Il memory model section (17.4) del JLS descrive in modo ragionevole la semantica di volatile e non volatile letture e scritture, nonché l'interazione con determinati altri costrutti come l'entrata e l'uscita del monitor.Può un confronto e uno scambio atomico sovrascrivere una scrittura pigra senza vederlo?

Tuttavia, non spiega completamente la semantica di compareAndSwaplazySet nelle classi java.util.concurrent.Atomic *. Per compareAndSet, si ha la fascetta dal package javadoc:

compareAndSet and all other read-and-update operations such as getAndIncrement 
have the memory effects of both reading and writing volatile variables. 

lazySet offre la fascetta pubblicitaria un po 'più imperscrutabile:

lazySet has the memory effects of writing (assigning) a volatile variable 
except that it permits reorderings with subsequent (but not previous) 
memory actions that do not themselves impose reordering constraints with 
ordinary non-volatile writes. Among other usage contexts, lazySet may apply 
when nulling out, for the sake of garbage collection, a reference that is 
never accessed again. 

Quello che non mi è chiaro è il modo in cui interagiscono. Se si emette un CAS (compareAndSet) e una lazySet per lo stesso valore atomico, in cui il CAS expectedValue è diverso dal valore lazySet, è possibile che il CAS sovrascrive il valore lazySet?

Più esplicitamente, dato due fili, T1 e T2, che operano su un comune AtomicInteger atomic = new AtomicInteger(); come segue:

static CountDownLatch latch = new CountDownLatch(2); 

T1 
atomic.lazySet(5); // L1A 
latch.countDown(); 
latch.await(); 
int val1 = atomic.get(); 

T2 
atomic.compareAndSet(0, 10); // L2A 
latch.countDown(); 
latch.await(); 
int val2 = atomic.get(); 

È val1 == val2 == 10 un possibile scenario qui? In effetti, può val1oval2 mai 10?

I latch non sono fondamentali per la domanda: sono solo un modo per far sì che entrambi i thread attenderanno fino a quando l'altro non è terminato, e forzare un evento prima tra le interessanti operazioni lazySet e compareAndSet su ciascun thread e il successivo legge l'atomico per vedere lo stato (senza di loro, si potrebbe certamente vedere almeno val2 == 10, transitoriamente).

risposta

2

compareAndSet è sia una lettura e scrittura, quindi fa imporre un vincolo scrittura ordinazione. Per la documentazione, questo significa che la scrittura lazySet sarà non essere permesso di essere riordinati intorno ad esso. Quindi no, val1 e val2 dovrebbe mai essere 10.

EDIT: Per chiarire, cosa lazySet fa essenzialmente è che essa agisce una scrittura atomica ai fini di qualsiasi altra operazione atomica che scrive anche alla stessa cosa, ma non atomico per altre operazioni atomiche che sono solo in lettura.

Più discussione potenzialmente utile in AtomicInteger lazySet vs. set, il bocconcino più utile è il link al changeset originale in cui sono stati aggiunti i metodi pigri: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329

+0

destro, ma la questione non è davvero di ri-ordinazione: infatti la 'lazySet' e' compareAndSwap' non si verificano sullo stesso thread, quindi non c'è un ordine inerente tra loro. Si verificheranno in qualche ordine, e la domanda è più o meno se la natura atomica di CAS vuol dire che non scriverà mai più la scrittura. – BeeOnRope

+0

L'ordine qui si riferisce alle operazioni di memoria, non alle istruzioni; quale thread sono attivi non è un fattore. CAS è un carico e un archivio - dal momento che lazySet applica un _preceeding store-store barrier_, se il CAS è già accaduto, allora la scrittura è garantita per essere completata prima che lazySet lo aggiorni. – tzaman

+0

Sì i memops sono le uniche istruzioni rilevanti. Quale thread sono attivi è importante, sullo stesso thread non ci sarebbero problemi.D'altra parte, le due operazioni su thread diversi non hanno ordine intrinseco. Fondamentalmente una frase del tipo: "questo significa che la scrittura lazySet non potrà essere riordinata attorno ad essa" ha senso per due operazioni sullo stesso thread, ma su thread diversi potrebbero verificarsi in entrambi gli ordini, tranne le restrizioni imposte da qualsiasi reale " si sincronizza con "operazioni in fase di esecuzione (ad esempio, una lettura volatile che vede una scrittura volatile da un altro thread). – BeeOnRope