-2

Due to many misunderstandings, I've reformulated this question from ground up. The intention of the question is unchanged. Many comments still refer to the old question text.

The documentation about volatile states that it ensures that other threads see memory updates in a consistent fashion. However, volatile is used rarely.

As far as I know, the purpose of synchronized blocks is to cause threads not to execute these critical sections simultaneously. Does synchronized also cause consistent memory updates to other threads, like volatile does?

Daniel S.
  • 6,458
  • 4
  • 35
  • 78
  • 1
    `Vector` is synchronized to prevent what you describe. (This was a design mistake; the synchronization is slow, usually unnecessary, and frequently inadequate when synchronization is needed.) Use an `ArrayList`, and you'll see your errors bite you more often. – user2357112 Nov 05 '15 at 00:50
  • 3
    Here's the problem: "*Obviously, this doesn't happen, or else I would have encountered such a problem during my career. I never did.*" – Andy Thomas Nov 05 '15 at 00:52
  • http://stackoverflow.com/questions/5816790/the-code-example-which-can-prove-volatile-declare-should-be-used – Sotirios Delimanolis Nov 05 '15 at 00:54
  • 2
    `Vector` is `synchronized` everywhere. `synchronized` provides a superset of the behavior of `volatile`. – Sotirios Delimanolis Nov 05 '15 at 00:55
  • 1
    Yes, writes (even to nonvolatile variables) in `synchronized` blocks are visible to reads of the same variables in blocks synchronized on the same lock that happen-after the writes. – Louis Wasserman Nov 05 '15 at 00:55
  • @AndyThomas :) :) well you know it's simply not true what you said. – Daniel S. Nov 05 '15 at 00:57
  • `volatile` doesn't refer to some sort of special thread-safe memory. It means that reads and writes to a `volatile` field establish specific *happens-before* relationships, the same way `synchronized` blocks and other thread synchronization tools do. It's not just about seeing a consistent series of values for the `volatile` variable itself; it's about what values you can see for other data guarded by the `volatile` variable. You really need to learn the Java Memory Model to understand the details. – user2357112 Nov 05 '15 at 01:01
  • Your statement *"volatile [...] ensures that modifications of two volatile fields by one thread will either be seen both by another threads"* is **incorrect**. Update of the first volatile will happen before the update of the second one, but another thread may see the first update and not the second. – Andreas Nov 05 '15 at 01:01
  • @Andreas you're right in that. I formulated this badly. But this doesn't affect the point I'm after, which is that if you omit the volatile, afaik, it is not guaranteed that if you see the change to the sencond one, you will also see the change to the first one. – Daniel S. Nov 05 '15 at 01:11
  • @DanielS. Correct, which is why your title is confusing. With volatile, update 1 happens before update 2, as seen by all threads. Without volatile, other threads *may* see update 2 before update 1. Therefore, all memory is **not** volatile in java. – Andreas Nov 05 '15 at 01:17
  • 1
    `it ensures that modifications of two volatile fields by one thread will either be seen both by another threads, or none will be seen by the other thread` No, you could definitely have a 2nd thread see only one modification out of two `volatile` variables. – markspace Nov 05 '15 at 01:21
  • @markspace see Andreas' comment and my answer to it. – Daniel S. Nov 05 '15 at 01:30

3 Answers3

5

is it simply true that all memory is consistently updated between threads in Java when happening inside a locked section?

Short answer:
Yes.

Long answer:

In JVMs, assignments of reference type and all primitive types except double and long is "atomic". I.e. any thread either sees one value or another, but never a half updated value. So you could even say memory is "consistently" updated without doing anything (there are some subtleties around this so don't try to actually use this characteristic! It's famously used to implement String#hashCode).

However, without volatile the changes may not be immediately visible, like you say ("immediately" is a bit misleading. For more details, see this answer). synchronized keyword does make changes immediately visible in the same way volatile does. So what's the point of volatile you ask.

Basically you can do anything what volatile can do using synchronized. So volatile isn't giving you new things you can do. However, it's still useful as it avoids locks. Performance is usually better with volatile (the trade-off is less features; synchronized can do everything volatile can, but not vice versa) and there's also no deadlock hazard. IMO if you can get away with volatile, you should use volatile. But there are a lot of people who disagree and think you should just use synchronized everywhere.

Community
  • 1
  • 1
Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
  • So you're saying that any memory changes taking place within a synchronized block are automatically made visible to all other threads immediately as soon as they enter another synchronized block on the same mutex object, is that correct? – Daniel S. Nov 05 '15 at 01:04
  • @DanielS. if it's synchronizing on the same object, yes (only one thread can acquire the lock at a time tho, so when one is executing in the block, no other thread is ) – Enno Shioji Nov 05 '15 at 01:07
  • 1
    `volatile` doesn't make any guarantees about changes being visible "immediately". It makes guarantees about consistency, but you could still get arbitrary delays on `volatile` writes propagating as long as the delays don't violate any happens-before constraints. – user2357112 Nov 05 '15 at 01:07
  • @user2357112: Yeah... Just thought I won't go into that, but I'll edit my answer. – Enno Shioji Nov 05 '15 at 01:08
  • @DanielS.: My other answer here may help, too http://stackoverflow.com/a/15654830/234901 – Enno Shioji Nov 05 '15 at 01:14
  • @DanielS. The way it's formally stated in the Java Language Spec, thread A _leaving_ a synchronized block "happens before" thread B _entering_ a block that is synchronized on the same object. So, whatever thread A wrote to memory before it exited the block is guaranteed to be visible to B after B synchronizes on the same object. – Solomon Slow Nov 05 '15 at 16:14
2

Java doesn't really have a concept of "volatile memory". Instead, the volatile keyword changes the guarantees the JVM makes about when and how a field will be written and read. Wikipedia has a decent breakdown of what Java (and other languages) mean by volatile.

Very roughly speaking, a volatile field is equivalent to a field that is always read-from and written-to like so:

// read
T local;
synchronized {
  local = field;
}

// ... do something with local

// write
synchronized {
  field = local;
}

In other words, reads and writes of volatile fields are atomic, and always visible to other threads. For simple concurrency operations this is sufficient, but you may well still need explicit synchronization to ensure compound operations are handled correctly. The advantage of volatile is that it's smaller (affecting exactly one field) and so can be handled more efficiently than a synchronized code block.

You'll notice from my psuedo-translation that any modifications or mutations to the field are not synchronized, meaning there is no memory barrier or happens-before relationship being imposed on anything you might do with the retrieved object. The only thing volatile provides is thread-safe field reads and writes. This is a feature because it's much more efficient than a synchronized block when all you need is to update a field.

I would strongly encourage you to read Java Concurrency in Practice if you haven't before; it provides an excellent overview of everything you need to know about concurrency in Java, including the difference between volatile and synchronized.


Obviously, this doesn't happen, or else I would have encountered such a problem during my career. I never did.

Note that this is a fallacious line of reasoning. It is perfectly possible for you to do something wrong yet never be affected by it or simply not notice its effects. For instance over-synchronized code (like Vector) will work correctly but run much slower than alternative solutions.

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • 1) volatile has more than the effect to consistently read/write a single long field on a 32 bit processor. 2) I know that reasoning fallacy very well, but look at my example: If Vector had a serious thread-safety-bug, one would have noticed with a probability so high that you can regard it as a certainty in your life. Not mathematically, but practically. – Daniel S. Nov 05 '15 at 01:27
  • Not quite correct: `volatile` has the same effect (synchronizes-with) as a monitor (the `synchronized` keyword). Both make the synchronized write, and *all previous writes*, visible to a thread that acquires the same variable. C.f. *Java Concurrency in Practice* (seriously, it's a very good book). Volatile is not "a single long field", it's much larger than that. – markspace Nov 05 '15 at 01:58
  • @DanielS. 1) I don't know what you mean by that - perhaps you could link to a citation? Like I said, my code snippet above is only approximately what happens, but it does reflect the intuition and memory effects in terms of synchronization. – dimo414 Nov 05 '15 at 02:23
  • 2) `Vector` is thread-safe because it is designed and documented to be thread-safe, not because you've never experienced an issue with it. That's the fallacy. Nevertheless, `synchronized` is not the only way to ensure thread-safety, and the very reason [`Volatile` is not recommended](http://stackoverflow.com/questions/1386275/why-is-java-vector-class-considered-obsolete-or-deprecated) in modern code is because it uses `synchronized` to provide thread-safety, instead of other, better patterns. – dimo414 Nov 05 '15 at 02:23
  • Hey, of course instead of "I've never encountered a problem with Vector", I could as well have written "we all agree Vector works". And still that it was designed and documented to be correct doesn't proof it is correct. Same thing there, too. Look at what I try to say instead of trying to get me wrong. – Daniel S. Nov 05 '15 at 02:44
  • I'm not "trying to get you wrong", I'm saying there is a real, intentional reason `Vector` is thread-safe. Java's memory model is actually very much based on proofs, mathematics, and theoretical computer science (e.g. [JLS §17.4.8](https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.8)), which is why we're able to discuss things like the *guarantees* the JVM provides. – dimo414 Nov 05 '15 at 03:11
0

Sure, using critical sections works. Using volatile works. But you have to use something to ensure you get the memory visibility you need. Otherwise, your code only works by luck or accident -- if it works.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278