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 compareAndSwap
né lazySet
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ò val1
oval2
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).
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
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
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