简体   繁体   中英

Why do I need to use synchronized for multiple threads over volatile?

Some people says if multiple threads are reading/writing then you need to use synchronized and if one thread is reading/writing and another one is only reading then you must use volatile. I don't get the difference between this situations.

Basically, the value of a volatile field becomes visible to all readers (other threads in particular) after a write operation completes on it.

Then If I define a variable as volatile, first threadA will read its value, threadA will update its value and write it to memory.After that variable will become visible to threadB. Then why do I need to synchronized block?

Some people says if multiple threads are reading/writing then you need to use synchronized and if one thread is reading/writing and another one is only reading then you must use volatile. I don't get the difference between this situations.

There really isn't a hard and fast rule with this. Choosing whether or not to use synchronized or volatile has more to do with how the objects are being updated as opposed to how many readers or writers there are.

For example, you can achieve multiple readers and writers with an AtomicLong which wraps a volatile long .

  private AtomicLong counter = new AtomicLong();
  ...
  // many threads can get/set this counter without synchronized
  counter.incrementAndGet();

And there are circumstances where you would need a synchronized block even with a single reader/writer.

synchronized (status) {
   status.setNumTransactions(dao.getNumTransactions());
   // we don't want the reader thread to see `status` partially updated here
   status.setTotalMoney(dao.getTotalMoney());
}

In the above example, since we are making multiple calls to update the status object we may need to ensure that other threads don't see it when the num-transactions has been updated but not the total-money. Yes, AtomicReference handles some of these cases but not all.

To be clear, marking a field volatile ensures memory synchronization. When you read a volatile field you cross a read memory barrier and when you write it you cross a write memory barrier. A synchronized block has a read memory barrier at the start and a write barrier at the end of the block and is has mutex locking to ensure only one thread can enter the block at once.

Sometimes you just need memory barriers to achieve proper sharing of data between threads and sometimes you need locking.

As comments suggest, you might do some further reading. But to give you an idea you can take a look at this stackoverflow question and think for example about the following scenario:

You have couple of variables which need to be in the right state. But although you make them all volatile you need time to update them by some code executing.

Exactly this code may be executed almost at the same time by a different thread. The first variables could be "OK" and somehow synchronized but some other maybe dependent on the first ones and are not correct yet. Thus you need a synchronized block in that case.

To add one more post for further reading about volatile look here

The primary difference between volatile and synchronized is that volatile only guarantees visibility whereas synchronized guarantees both visibility and locking.

If there are multiple read threads and one write thread then volatile usage can ensure that changes by the write thread to the volatile variable are visible to other threads immediately. But you see in this case locking isn't a problem because you only have 1 writing thread.

There are certain rules of thumb for a volatile:

  1. Don't use volatile when its value depends on its previous value
  2. Don't use volatile when it participates in interactions with other invariants
  3. Don't use volatile when there are multiple write threads that update value of volatile variable.

In general, use of volatile should be limited to only those cases where it's relatively easy to reason about its state such as in the case of status flags.

In all other cases where you have shared mutable state always use synchronized wherever shared mutable state is being touched unless declared final and modified only in the constructor without unsafe publication. Volatile is a replacement for synchronized only in special cases as described in my 3 points.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM