This is about volatile piggyback. Purpose: I want to reach a lightweight vars visibilty. Consistency of a_b_c is not important. I have a bunch of vars and I don't want to make them all volatile.
Is this code threadsafe?
class A { public int a, b, c; volatile int sync; public void setup() { a = 2; b = 3; c = 4; } public void sync() { sync++; } } final static A aaa = new A(); Thread0: aaa.setup(); end Thread1: for(;;) {aaa.sync(); logic with aaa.a, aaa.b, aaa.c} Thread2: for(;;) {aaa.sync(); logic with aaa.a, aaa.b, aaa.c}
Volatile variables have the visibility features of synchronized but not the atomicity features. The values of the volatile variable will never be cached and all writes and reads will be done to and from the main memory.
When to use it? You can use a volatile variable if you want to read and write long and double variable automatically. It can be used as an alternative way of achieving synchronization in Java. All reader threads will see the updated value of the volatile variable after completing the write operation.
The volatile keyword is intended to prevent the compiler from applying any optimizations on objects that can change in ways that cannot be determined by the compiler. Objects declared as volatile are omitted from optimization because their values can be changed by code outside the scope of current code at any time.
Unlike synchronized methods or blocks, it does not make other threads wait while one thread is working on a critical section. Therefore, the volatile keyword does not provide thread safety when non-atomic operations or composite operations are performed on shared variables.
Java Memory Model defines the happens-before relationship which has the following properties (amongst others):
These two properties together with transitivity of the happens-before relationship imply the visibility guarantees that OP seeks in the following manner:
a
in thread 1 happens-before a write to sync
in a call to sync()
in thread 1 (program order rule).sync
in the call to sync()
in thread 1 happens-before a read to sync
in a call to sync
in thread 2 (volatile variable rule).sync
in the call to sync()
in thread 2 happens-before a read from a
in thread 2 (program order rule).This implies that the answer to the question is yes, i.e. the call to sync()
in each iteration in threads 1 and 2 ensures visibility of changes to a
, b
and c
to the other thread(s). Note that this ensures visibility only. No mutual exclusion guarantees exist and hence all invariants binding a
, b
and c
may be violated.
See also Java theory and practice: Fixing the Java Memory Model, Part 2. In particular the section "New guarantees for volatile" which says
Under the new memory model, when thread A writes to a volatile variable V, and thread B reads from V, any variable values that were visible to A at the time that V was written are guaranteed now to be visible to B.
Incrementing a value between threads is never thread-safe with just volatile
. This only ensures that each thread gets an up to date value, not that the increment is atomic, because at the assembler level your ++ is actually several instructions that can be interleaved.
You should use AtomicInteger
for a fast atomic increment.
Edit: Reading again what you need is actually a memory fence. Java has no memory fence instruction, but you can use a lock for the memory fence "side-effect". In that case declare the sync method synchronized to introduce an implicit fence:
void synchronized sync() { sync++; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With