-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?

user207421
  • 305,947
  • 44
  • 307
  • 483
hellzone
  • 5,393
  • 25
  • 82
  • 148
  • 3
    I would suggest you do some [independent reading](https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html). This question is much more complex that you realise. But for a simple example - what if I want to set **two** variables atomically? – Boris the Spider Mar 27 '17 at 20:40
  • Also recommended: "Java Concurrency in Practice" – dnault Mar 27 '17 at 20:41
  • @dnault that would seem a little too advanced given then question... – Boris the Spider Mar 27 '17 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. – hellzone Mar 27 '17 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... – Boris the Spider Mar 27 '17 at 20:55
  • Values of `volatile` fields never "become​ unvisible [sic]" to other threads. With two `volatile` fields, a thread could write to the first, another thread could change that value, then the first thread might change the second. Now threads will see the first field as set by the second thread, and the second field as set by the first thread. With `c++`, a thread could read `c`, then another thread could read `c`, then each thread could apply the increment to `c`, and `c` ends up only increasing by `1`, not `2`. – Lew Bloch Mar 27 '17 at 21:22
  • @LewBloch then what volatile keyword does if all threads can access field? "the volatile modifier guarantees that any thread that reads a field will see the most recently written value." how it guarantees that? – hellzone Mar 27 '17 at 21:34
  • @hellzone as I mentioned, you need a much better understanding of how basic concurrency constructs work to understand why `volatile` is useful. You need an _even_ better understanding to learn how it works. Fundamentally is guarantees _visibility_ but not _atomicity_. – Boris the Spider Mar 27 '17 at 21:37
  • It guarantees that by the compiler inserting instructions in the bytecode to force a _memory barrier_ so that all writes, not just to the `volatile` variable, prior to the write to the variable become visible to other threads after they read the `volatile` variable. But that has nothing to do with what I said, which is that _between_ writes to a `volatile` variable stuff can happen. Frankly, your refusal to follow everyone's advice to _study the subject yourself_ is wasting everyone's time. Have some respect. – Lew Bloch Mar 27 '17 at 21:39
  • Possible duplicate of [volatile variables, synchronized blocks](http://stackoverflow.com/questions/23678620/volatile-variables-synchronized-blocks) – Solomon Slow Mar 28 '17 at 01:31

3 Answers3

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.

Gray
  • 115,027
  • 24
  • 293
  • 354
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

Community
  • 1
  • 1
edi
  • 917
  • 7
  • 17
  • 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 Mar 27 '17 at 21:04
  • 1
    @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. – Boris the Spider Mar 27 '17 at 21:10
  • @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? – edi Mar 27 '17 at 21:12
  • @BoristheSpider Thanks for the example! – edi Mar 27 '17 at 21:16
  • @BoristheSpider Then synchronized extends volatile and we can always use synchronized instead of volatile. – hellzone Mar 27 '17 at 21:30
  • @hellzone you asked "_why do I need to use synchronized for multiple threads over volatile?_" This seems to answer your question. I don't understand the comment. Also I have no clue what "_[t]hen synchronized extends volatile_" means. – Boris the Spider Mar 27 '17 at 21:31
  • @hellzone, synchronized and volatile are two keywords in java for different purpose. synchronized does not extend volatile since it's not a class. volatile serves memory visibility and synchronized serves memory consistency – Ravindra babu Mar 29 '17 at 15:42
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.

Avneet Paul
  • 293
  • 1
  • 7
  • The `AtomicLong` and other objects successfully use `volatile` but still support `incrementAndGet()` so that violates your #1 and #2. They also allow multiple writers. – Gray Mar 28 '17 at 16:56