Mike. J. Thompson wrote:Just by adding the volatile keyword we have created a happens-before relationship between writes to keepRunning and subsequent reads. This means that when thread2 calls stop() thread1 will see the effect of that call at some point in the future and will stop. ... In some situations this is required because the volatile keyword cannot make everything threadsafe, but synchronization and locks will be less perforant.
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:
Like Tushar, cow for the explanation; but I'm not entirely sure that the effect of your code is quite the same as full synchronization - but I could be wrong; especially for a boolean.
I've always taken volatile to mean "read-synchronized", but not necessarily write-synchronized, and I seem to remember examples involving increments, where simply adding volatile wasn't sufficient to ensure correct updates.
A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order).
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
Winston Gutkowski wrote:TBH, I've yet to find a really good example (or explanation) of "happens before" so, as I say, I could be wrong. And if you know of one, I'd be really grateful if you could post it.
Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.
...
It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.
For example, the write of a default value to every field of an object constructed by a thread need not happen before the beginning of that thread, as long as no read ever observes that fact.
Mike. J. Thompson wrote:You are correct that just adding volatile will not ensure desired behaviour in all situations. It doesn't guarantee the ordering that instructions are run from different threads (so doesn't provide mutual-exclusion as Tushar mentioned).
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Winston Gutkowski wrote:I understand that the compiler is allowed to reorder instructions providing they produce the same outcome, and that volatile restricts this so that (I presume) every read and write done to such a variable is done in sequence for a particular Thread; but how does that help unless other Threads are guaranteed to see the result of the latest update done by any Thread?
I understand that order between Threads can't be guaranteed, but isn't this also true of synchronization? For any given race-condition you can't predict which Thread will acquire the lock first and, once released, you can't predict which Thread in the queue (if there is one) will acquire it next.
Stephan van Hulst wrote:Volatile guarantees that when one thread assigns a new value to the stops variable, all other threads will see that update immediately. However, because the ++ operator isn't atomic, one thread may read the value before another writes to it, and then write the incremented value, overwriting the other write operation.
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
The Java® Language Specification wrote:For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.
Writes and reads of volatile long and double values are always atomic.
Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.
Stephan van Hulst wrote:Writes and reads of volatile long and double values are always atomic.
Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
Mike. J. Thompson wrote:Writes to references are atomic, but [...] This is why double-checked locking never worked.
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here