Tom Hobbs wrote:
Yes, you're right.
I knew about the non-atomicity of ++, my concern was a call to reset
creeping in between the two parts of that operation.
That is a very good point.
Leaving reset unsynchronized, even with volatile, would lead to results
that would not be possible with full synchronization. Suppose thread A
is going to do a reset, and thread B is going to do an increment, and
everybody agrees the count is currently 10.
With synchronization, after both operations have completed, count is
either 1 (A:reset, B:increment) or 0 (B:increment, A:reset).
With only increment synchronized, even if the the count is volatile, we
add the possible outcome 11, which cannot be reached by executing the
two methods atomically:
B: volatile read, result 10
A: volatile write of 0
B: volatile write of 11
I think it is best to stick to synchronization and the
java.util.concurrent classes, ignoring volatile, except in really
important performance-critical situations. If we do find we need to use
volatile, I would like to take the time to do a formal
proof-of-correctness based on the JLS rules.
I forgot about the "Get a global lock on the variable" that volatile
would require as mentioned here;
http://www.javaperformancetuning.com/news/qotm051.shtml
I don't think we can depend on anything other than the JLS, or possibly
"Java Concurrency in Practice" which seems to tend towards safety if it
simplifies the situation at all.
For example, I would be surprised if a SPARC v.9 TSO implementation of
volatile needed to do more than a "membar #StoreLoad" between a store to
a volatile variable and the next load of anything. Even on a system that
needed to do more, any locking would treat the volatile read and the
volatile write of the ++ as two separate operations.
Patricia