2

I have few doubts about synchronized blocks. Before my questions I would like to share the answers from another related post Link for Answer to related question. I quote Peter Lawrey from the same answer.

  1. synchronized ensures you have a consistent view of the data. This means you will read the latest value and other caches will get the latest value. Caches are smart enough to talk to each other via a special bus (not something required by the JLS, but allowed) This bus means that it doesn't have to touch main memory to get a consistent view.

  2. If you only use synchronized, you wouldn't need volatile. Volatile is useful if you have a very simple operation for which synchronized would be overkill.

In reference to above I have three questions below :

Q1. Suppose in a multi threaded application there is an object or a primitive instance field being only read in a synchronized block (write may be happening in some other method without synchronization). Also Synchronized block is defined upon some other Object. Does declaring it volatile (even if it is read inside Synchronized block only) makes any sense ?

Q2. I understand the value of the states of the object upon which Synchronization has been done is consistent. I am not sure for the state of other objects and primitive fields being read in side the Synchronized block. Suppose changes are made without obtaining a lock but reading is done by obtaining a lock. Does state of all the objects and value of all primitive fields inside a Synchronized block will have consistent view always. ?

Q3. [Update] : Will all fields being read in a synchronized block will be read from main memory regardless of what we lock on ? [answered by CKing]

I have a prepared a reference code for my questions above.

public class Test {
  private SomeClass someObj;
  private boolean isSomeFlag;
  private Object lock = new Object();
  public SomeClass getObject() {
        return someObj;
  }
  public void setObject(SomeClass someObj) {
        this.someObj = someObj;
  }
  public void executeSomeProcess(){
        //some process...
  }
  // synchronized block is on a private someObj lock.
  // inside the lock method does the value of isSomeFlag and state of someObj remain consistent?

  public void someMethod(){
        synchronized (lock) {
              while(isSomeFlag){
                    executeSomeProcess();
              }
              if(someObj.isLogicToBePerformed()){
                    someObj.performSomeLogic();
              }
        }
  }
  // this is method without synchronization.
  public void setSomeFlag(boolean isSomeFlag) {
        this.isSomeFlag = isSomeFlag;
  }
}
Community
  • 1
  • 1
nits.kk
  • 5,204
  • 4
  • 33
  • 55
  • 1
    I'd like to be nice about this, but that's one of those things where honesty works best.. If you're thinking about things like "fetch from memory" while talking about the JMM you haven't understood it and should stay away from concurrency. But no the code as given is incorrect. – Voo Feb 10 '17 at 15:57
  • making `isSomeFlag` volatile will fix this – ControlAltDel Feb 10 '17 at 16:00
  • @Voo I have edited my question, sorry for using the word memory, i meant consistent.. – nits.kk Feb 10 '17 at 16:06
  • 1
    @ControlAltDel No, simply making `isSomeFlag` volatile will not fix the problems with this code. You also have a data race on `someObj`, meaning that its possible that `someMethod()` will see scrambled nonsense when it goes to access `someObj....`. ("Just add volatile here" is almost always dangerous advice.) – Brian Goetz Feb 10 '17 at 16:55
  • @BrianGoetz , sir can you please add an answer too , it will really be helpful for me to clear my concepts on this... – nits.kk Feb 10 '17 at 16:58
  • @Brian Goetz Thanks :) – nits.kk Feb 10 '17 at 17:03
  • 2
    @BrianGoetz That was smooth. [I can't believe I got to witness this ;) ] – Chetan Kinger Feb 10 '17 at 17:08
  • 1
    @CKing Yeah that's a bit like getting help with your algorithm homework by Don Knuth without even noticing :-) – Voo Feb 10 '17 at 17:47
  • @Voo What would you say if I told you I am hearing that name for the first time. I guess I jumped straight into Java and never spent much time on the science part of computers :( – Chetan Kinger Feb 10 '17 at 17:52
  • 2
    @CKing I'd say practically speaking it doesn't matter at all :-) Although looking him up on Wikipedia might be a well spent 15 minutes, he's quite the interesting character. – Voo Feb 10 '17 at 17:58
  • Java Concurrency in Practice by brian goetz.. "Architect at Oracle Corporation, and was the specification lead for JSR-335 (Lambda Expressions for the Java Programming Language.)".I am actually honored to have his comment on my question ... and feel sorry to have not noticed – nits.kk Feb 10 '17 at 18:03
  • 1
    @nits.kk I was talking about not knowing Don Knuth. I believe every Java programmer eventually crosses paths with the legendary book on concurrency. Your time was today :) – Chetan Kinger Feb 10 '17 at 18:07
  • @Voo I looked him up. This guy is amazing. Finders fee. He got candies for solving a complex problem that most people can't. Conflicted between choosing physics and music, etc. Thanks for the mention :) – Chetan Kinger Feb 10 '17 at 18:10

3 Answers3

3

The first thing you need to understand is that there is a subtle difference between the scenario being discussed in the linked answer and the scenario you are talking about. You speak about modifying a value without synchronization whereas all values are modified within a synchronized context in the linked answer. With this understanding in mind, let's address your questions :

Q1. Suppose in a multi threaded application there is an object or a primitive instance field being only read in a synchronized block (write may be happening in some other method without synchronization). Also Synchronized block is defined upon some other Object. Does declaring it volatile (even if it is read inside Synchronized block only) makes any sense ?

Yes it does make sense to declare the field as volatile. Since the write is not happening in a synchronized context, there is no guarantee that the writing thread will flush the newly updated value to main memory. The reading thread may still see inconsistent values because of this.

Suppose changes are made without obtaining a lock but reading is done by obtaining a lock. Does state of all the objects and value of all primitive fields inside a Synchronized block will have consistent view always. ?

The answer is still no. The reasoning is the same as above.

Bottom line : Modifying values outside synchronized context will not ensure that these values get flushed to main memory. (as the reader thread may enter the synchronized block before the writer thread does) Threads that read these values in a synchronized context may still end up reading older values even if they get these values from the main memory.


Note that this question talks about primitives so it is also important to understand that Java provides Out-of-thin-air safety for 32-bit primitives (all primitives except long and double) which means that you can be assured that you will atleast see a valid value (if not consistent).

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
  • Ok but what about the linked answer, It says : 1. synchronized ensures you have a consistent view of the data. This means you will read the latest value and other caches will get the latest value. and 2. If you only use synchronized, you wouldn't need volatile. Volatile is useful if you have a very simple operation for which synchronized would be overkill. Are they not somewhat not correct or complete ? – nits.kk Feb 10 '17 at 16:55
  • 1
    There is a subtle difference between the scenario being discussed in the linked answer and the scenario you are talking about. You speak about modifying a value without synchronization whereas all values are modified within a synchronized context in the linked answer. Modifying values outside synchronized context will not ensure that they get flushed to main memory. – Chetan Kinger Feb 10 '17 at 16:59
  • 1
    @nits.kk If this answer answers your direct question better than the other answers, then don't forget to upvote and accept it. – Chetan Kinger Feb 10 '17 at 17:02
  • +1 for the point that changes done in non synchronized contect may not be flushed to main memory. But please answer my related doubt .. you said synchronized contects -> reading done from main memory. Is this true for all the variables inside the synchronized block ( suppose lock on ObjectA and objectB is being read, will its state be read from main memory (not necessarily latest values, but main memory reads guaranteed) even if its read within synchronized block on ObjectA ?) – nits.kk Feb 10 '17 at 17:10
  • 1
    Yes. All fields being read in a synchronized block will be read from main memory regardless of what you lock on. That said, if you want the reading thread to always see the updates made by the writing thread, they both need to lock on the same object. I hope this answers all your doubts? – Chetan Kinger Feb 10 '17 at 17:13
  • I have edited your answer with the answer you gave in comments . Thanks a lot for the help. Edit is due for peer review, you may edit it to add : Also As writing done in non synchronized way may not lead the values being flushed to main memory (if fields are non volatile) but All fields being read in a synchronized block will be read from main memory regardless of what you lock on. This means values may not be the latest due to writing not done in synchronized way but values will be fetched from main memory if reading is done in synchronized block. – nits.kk Feb 10 '17 at 17:19
  • 1
    I couldn't see the edit as it was already rejected by the community. But yes, your understanding is absolutely correct. – Chetan Kinger Feb 10 '17 at 17:23
1

All synchronized does is capture the lock of the object that it is synchronized on. If the lock is already captured, it will wait for its release. It does not in any way assert that that object's internal fields won't change. For that, there is volatile

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
1

When you synchronize on an object monitor A, it is guaranteed that another thread synchronizing on the same monitor A afterwards will see any changes made by the first thread to any object. That's the visibility guarantee provided by synchronized, nothing more.

A volatile variable guarantees visibility (for the variable only, a volatile HashMap doesn't mean the contents of the map would be visible) between threads regardless of any synchronized blocks.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • thanks for the answer. If suppose synchronization has been done on monitor of 'ObjectA' , and we read state of 'ObjectB' (it is being modified in some other method by some thread) inside the synchronized block, will it be consistent ? – nits.kk Feb 10 '17 at 16:14
  • 1
    Not unless the modifications to `ObjectB` were made in a `synchronized(ObjectA)` block. Same monitor -> changes visible. Different monitors -> no guarantee. – Kayaman Feb 10 '17 at 16:18
  • Great.. Actually this is something very near to what i wanted to know. Just to make my self clear one question : Changes to all the fields (and not just the object on which synchronization is done) are visible, if changes are done on same monitor ? – nits.kk Feb 10 '17 at 16:22
  • 1
    The object monitor on which you synchronize is irrelevant, as you can see from your code with `Object lock`. But when multiple threads sync on the same one, *any* changes to *any* objects are guaranteed to be visible from one to another. – Kayaman Feb 10 '17 at 16:28
  • Thanks :) Can you please include this in your answer as well. I will mark it as accepted. It gives more clarity to the answer as per the question I have asked. – nits.kk Feb 10 '17 at 16:30