3

Lets say I have two threads A and B and inside these both 2 threads I have synchronized block in which an int variable is modified continously. For example, thread A enter synchronized block modify int variable then call these 2 methods:

notifyall(); //to wake thread B which is in waiting state and
wait(): 

and after that thread B acquire lock and do same steps as thread A and process keep on repeating. All changes to int variable happens inside synchronized block of both threads.

My question is do I need to make int variable volatile. Do thread flush to main memory before they go to waiting state and reload data in registers when thread acquire lock again as a result of notifyall(); call.

anujprashar
  • 6,263
  • 7
  • 52
  • 86

3 Answers3

5

If A and B run alternatively rather than concurrently, and if they switch off via wait() and notifyAll() invocations on the same Object, and if no other threads access the variable in question, then thread safety does not require the variable to be volatile.

Note that o.wait() and o.notifyAll() must be invoked inside a method or block synchronized on o -- that synchronization is sufficient to ensure that the two threads see all each others' writes to any variable before the switch-off.

Do be careful to ensure that the two threads are synchronizing on the same object, which is not clear from your question. You have no effective synchronization at all if, say, the two threads are waiting on and notifying different instances of the same class.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thanks for reply. Ofcourse object is same for synchronization. So is it guaranteed that thread will update its cache and write to main memory when we call wait(); and notifyall(); and variable is non-volatile. – anujprashar Oct 31 '14 at 19:51
  • 1
    Not exactly. It is more a function of synchronization on the same object. In Java Memory Model terms, an unlock on a monitor 'happens before' every subsequent lock on that same monitor. When you alternate between threads via `wait()` and `notifyAll()`, each switch involves an unlock by the running thread followed by a lock by the other. Java doesn't actually specify low-level details such as cache flushing, but in fact that's how the memory model's requirements are typically met. – John Bollinger Oct 31 '14 at 20:02
  • +1 From my understanding of this, the volatile keyword updates a single variable (ie the volatile variable) synchronized also establishes this happens before relationship, but does so to all of the variables which have been accessed from main memory. So it may be that synchronized results in more overhead in some situations. In my experience is almost always been a one or the other type of thing. Either your variable is volatile, or modifications are made in a synchronized context. If youre paranoid, you can always use atomic types, if a suitable one is available ... – Mark W Oct 31 '14 at 20:22
  • @MarkW In JMM terms, a write to a `volatile` variable 'happens before' every subsequent read of that variable. That is exactly the same kind of relationship that an unlock of a monitor has with subsequent locks of that same monitor. `volatile` is therefore not any lighter weight than standard synchronization, but if you have no other reason for explicit synchronization then it is rather less wordy. If you are using `wait()` and `notify()`, however, then you need explicit synchronization. – John Bollinger Oct 31 '14 at 20:29
  • The java performance turning team disagrees with you int he following quote: " Brian Goetz confirms that with the latest Java memory model, volatile-read and monitor-acquire have the same memory semantics, and volatile-write and monitor-release have the same memory semantics, so a volatile operation can never be more expensive than the corresponding monitor operation, and could be less." -http://www.javaperformancetuning.com/news/qotm051.shtml. But otherwise great answer! – Mark W Oct 31 '14 at 20:31
  • @MarkW evidently Goetz and I agree about the memory semantics, but the conclusion about comparative expense does not follow from there. Perhaps the context of the quotation would make the justification for that conclusion clearer. – John Bollinger Oct 31 '14 at 20:39
  • I believe its only related to the fact that you can synchronized on a single object and modify many shared variables in that scope, where as a volatile member is singular by definition. This can result in more writes to memory. I find it hard to construct a situation where it would matter, and its something you would almost never have to account for, but the statement volatile is not more expensive than synchronized isnt *quite* true. And thats not considering JIT... – Mark W Oct 31 '14 at 20:41
  • @MarkW I'm generally not buying the article's analysis. The JMM is pretty clear that volatile-write followed by volatile-read has exactly the same implications on memory (including other variables') as monitor-unlock followed by monitor-lock. If a particular VM happens to implement those requirements differently for the two alternatives then perhaps one (it's not clear which) would have an advantage *in that VM*. As far as the language itself, though, synchronization is neither inherently more nor inherently less expensive than volatile access. – John Bollinger Oct 31 '14 at 21:08
  • I agree with you within the context of modifying a single field, but there are other things to be considered when you establish a synchronized scope. The opinion wasn't that of the performance tuning team, but of Brian Goetz, java language architect. I may not entirely understand his reasons, but am inclined to take him seriously. – Mark W Oct 31 '14 at 21:10
  • @MarkW I take Goetz seriously, too, but the analysis presented in that article is simply not consistent with the requirements of the JMM. Even smart people miss the ball from time to time. – John Bollinger Oct 31 '14 at 21:14
  • In defense of Goetz, those comments were published less than six months after the approval of JSR-133. It looks like they are directed at the pre-JSR-133 memory model, not the current one. – John Bollinger Oct 31 '14 at 21:20
  • Weird that another recent question here on SO is in regards to Goetz eh? http://stackoverflow.com/questions/26683441/brian-goetzs-improper-publication – Mark W Oct 31 '14 at 21:28
  • I saw that, yes. Nearly fell out of my chair. – John Bollinger Oct 31 '14 at 21:43
  • @John Bollinger: `synchronized` provides mutual exclusion of access which includes the possibility that threads have to be added to a waiting queue and excluded from task scheduling. That’s all *additional* to the memory semantics which are that a `synchronized` block includes *both* a barrier like a `volatile` read (at the beginning) *and* a write (at the end). What’s so hard to understand that this can’t be cheaper than *one* single `volatile` access being *either* read or write? – Holger Nov 03 '14 at 13:19
  • @Holger, in fact, the JLS does not *require* any of that. It takes care to place as few implementation requirements as possible. It does describe the allowed observable behaviors using some of those terms, but in the end, all behaviors permitted to programs that use volatile access to a given variable are also allowed to programs that instead use synchronized access to a normal variable (absent any other inter-thread actions). Since Java therefore permits implementations to handle them *exactly the same way*, `volatile` access has no inherent general advantage at the language level. – John Bollinger Nov 04 '14 at 16:25
  • @John Bollinger: [JLS §14.19](http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.19): “A synchronized statement acquires a mutual-exclusion lock … executes a block, then releases the lock. While the executing thread owns the lock, no other thread may acquire the lock.” Clearly specified without any ambiguity. Accessing volatile variables doesn’t acquire any locks, hence, when you don’t want to acquire a lock, using `volatile` variables *has* an advantage. If not regarding performance then it still has the advantage of using the language tools as intended. – Holger Nov 05 '14 at 09:20
2

The answer is no you do not need to make the variable volatile. The reasoning being, writes that occur to a variable within a synchronized block will be visible to subsequent threads entering a synchronized block on the same object.

So it has the same memory semantics as a volatile read and write.

John Vint
  • 39,695
  • 7
  • 78
  • 108
0

Not sure about java. But in C: https://www.kernel.org/doc/Documentation/volatile-considered-harmful.txt

If shared_data were declared volatile, the locking would still be necessary. But the compiler would also be prevented from optimizing access to shared_data within the critical section, when we know that nobody else can be working with it. While the lock is held, shared_data is not volatile. When dealing with shared data, proper locking makes volatile unnecessary - and potentially harmful.

Amit Sharma
  • 1,987
  • 2
  • 18
  • 29
  • The example you given is of c. I am not sure if Java memory model is same as multi-threading in c. – anujprashar Oct 31 '14 at 19:58
  • Java's `volatile` has different semantics than C's. In particular, the Java Memory Model specifies that every write to a volatile variable 'happens before' every subsequent read of that variable, so declaring a variable `volatile` does make it safe for different threads to read and write it without additional synchronization. For a certain situation-dependent definition of "safe". – John Bollinger Oct 31 '14 at 20:10