Do we need to synchronize writes if we are synchronizing reads?
Asked Answered
B

3

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;
  }
}
Bordelon answered 10/2, 2017 at 15:52 Comment(13)
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.Folderol
making isSomeFlag volatile will fix thisEyeful
@Folderol I have edited my question, sorry for using the word memory, i meant consistent..Bordelon
@Eyeful 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.)Nonattendance
@BrianGoetz , sir can you please add an answer too , it will really be helpful for me to clear my concepts on this...Bordelon
@Brian Goetz Thanks :)Bordelon
@BrianGoetz That was smooth. [I can't believe I got to witness this ;) ]Silent
@CKing Yeah that's a bit like getting help with your algorithm homework by Don Knuth without even noticing :-)Folderol
@Folderol 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 :(Silent
@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.Folderol
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 noticedBordelon
@Bordelon 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 :)Silent
@Folderol 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 :)Silent
S
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).

Silent answered 10/2, 2017 at 16:52 Comment(7)
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 ?Bordelon
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.Silent
@Bordelon If this answer answers your direct question better than the other answers, then don't forget to upvote and accept it.Silent
+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 ?)Bordelon
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?Silent
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.Bordelon
I couldn't see the edit as it was already rejected by the community. But yes, your understanding is absolutely correct.Silent
E
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

Eyeful answered 10/2, 2017 at 15:57 Comment(1)
Thanks for the reply, I mistakenly used main memory, I have edited the question..Bordelon
A
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.

Auberbach answered 10/2, 2017 at 16:11 Comment(5)
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 ?Bordelon
Not unless the modifications to ObjectB were made in a synchronized(ObjectA) block. Same monitor -> changes visible. Different monitors -> no guarantee.Auberbach
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 ?Bordelon
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.Auberbach
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.Bordelon

© 2022 - 2024 — McMap. All rights reserved.