-1

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?

10
  • 3
    I would suggest you do some independent reading. This question is much more complex that you realise. But for a simple example - what if I want to set two variables atomically? Commented Mar 27, 2017 at 20:40
  • Also recommended: "Java Concurrency in Practice" Commented Mar 27, 2017 at 20:41
  • @dnault that would seem a little too advanced given then question... Commented Mar 27, 2017 at 20:42
  • @BoristheSpider When you try to set two variables atomically, you will define both variables with volatile and value of volatile fields will become unvisible to all other threads until first thread finishes its job. Your link supports my idea by the way. If you define c variable as volatile, you don't need to synchronized methods anymore. Commented Mar 27, 2017 at 20:54
  • 3
    @hellzone very, very wrong and very dangerous words. c++ and c-- are not atomic operations and volatile won't help you. Welcome to the world of concurrency... Commented Mar 27, 2017 at 20:55

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

7 Comments

Value of a volatile variable will become unvisible to all other threads. How "code may be executed almost at the same time by a different thread"?
@hellzone but in the example, two variables need to be updated. Lets say I have a class ConcurrentList, now I have a data and a size. I need to 1) write to the data and 2) update the size atomically. If I update the size first, and allow other threads to read it, they will read data that isn't yet there. If I update the data first then other threads may overwrite my data as the size is not set. volatile is a very specialised concurrent construct.
@hellzone maybe I'm missing something but why would the variables become invisible to all other threads? My understanding of volatile is that read and write goes directly to main memory (no caching) - that's all - no blocking/no cloaking. Also for the second question. Thread A calls function x() and Thread B calls function x() - why shouldn't that be possible?
@BoristheSpider Thanks for the example!
@BoristheSpider Then synchronized extends volatile and we can always use synchronized instead of volatile.
|
0

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.

1 Comment

The AtomicLong and other objects successfully use volatile but still support incrementAndGet() so that violates your #1 and #2. They also allow multiple writers.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.