Java – synchronization difference between field reading and volatile
In a good article with some concurrency tips, an example is optimized to the following lines:
double getBalance() { Account acct = verify(name,password); synchronized(acct) { return acct.balance; } }
If I understand correctly, the key point of synchronization is to ensure that the value of acct.balance read by this thread is up-to-date, and any pending writes to the fields of objects in acct.balance are also written to main memory
This example makes me think: is it more effective to just declare acct.balance (i.e. domain balance of the account)? It should be more efficient, save all synchronization of access to acct.balance, and do not lock the entire acct object Did I miss anything?
Solution
You're right. Volatile provides visibility assurance Synchronization provides visibility assurance and serialization of protected code segments For very simple cases, volatile is enough, but using volatile instead of synchronization is easy to get into trouble
If you think the account has a way to adjust the balance, the volatility is not good enough
public void add(double amount) { balance = balance + amount; }
So if the balance is fluctuating and there is no other synchronization, we have a problem If two threads try and call add () together, you may have a "missed" update. The following happens
Thread1 - Calls add(100) Thread2 - Calls add(200) Thread1 - Read balance (0) Thread2 - Read balance (0) Thread1 - Compute new balance (0+100=100) Thread2 - Compute new balance (0+200=200) Thread1 - Write balance = 100 Thread2 - Write balance = 200 (WRONG!)
Obviously, this is wrong because two threads read the current value and update it independently, and then write it back (read, calculate, write) Volatile doesn't help here, so you need synchronization to ensure that one thread completes the entire update before other threads start
I generally find that if I think "I can use volatile instead of synchronization" when writing some code, the answer may be "yes", but it is not worth the benefit (secondary performance) to accurately determine its time / effort and the risk of error
Except for a well - written account class, it can handle all synchronization logic internally, so callers don't have to worry