I have two classes.
One class is just a container for a integer value with get and set synchronized methods.
public class Sync {
private int dataSync;
public synchronized int getDataSync() {
return dataSync;
}
public synchronized void setDataSync(int data) {
dataSync = data;
}
}
The other classes is similar. It is just a container for a integer value with get and set methods without synchronization.
public class NotSync {
private int dataNotSync;
public int getDataNotSync() {
return dataNotSync;
}
public void setDataNotSync(int data) {
dataNotSync = data;
}
}
Now my question is "is 10 value guaranteed to be visible to all other threads" at the end of the run method.
public class RunSync {
public static void main(String[] args) {
RunSync rs = new RunSync();
rs.run();
}
private NotSync dataNS;
private Sync dataS;
private int data;
public RunSync() {
dataS = new Sync();
dataNS = new NotSync();
}
public synchronized void run() {
data = 100;
dataS.setDataSync(45);
dataNS.setDataNotSync(10);
//Question A: is 10 value guaranteed to be visible to all other
//threads when method exits?
//we are inside a synchronized block aren't we?
//so all writes must be flushed to main memory
}
}
EDIT: Imagine there are other threads. This is just a quickly written example. Question goes to what is exactly guaranteed to flushed back to main memory when a synchronize block finishes.
EDIT2: According to the java memory model "changes to fields made by one thread are guaranteed to be visible to other threads only under some conditions. One condition is A writing thread releases a sync lock and a reading thread subsequently acquires that same synch lock.
So if another thread acquires the RunSync lock, will it be guaranteed to see 10 in NotSync instance of RunSync? Even though NotSync is not protected?
Edit3: related question without a definitive answer. I am still looking. What is the scope of memory flushed or published to various threads when using volatile and synchronized?
EDIT4: To simplify the example what about this method from RunSync class
public synchronized void run2() {
dataNS.setDataNotSync(10);
}
When run2 exits, nothing is guaranteed to be flushed to main memory? A definite answer to this will answer my question. If No. that means only members of the lock are guaranteed to be flushed back, and will be visible to other threads provided the other threads acquires that same lock on RunSync. Answer is No Guarantee.
EDIT5: and in this case, is the assert guaranteed to be true?
public class RunSync {
public volatile boolean was10Written = false;
public synchronized void run2() {
dataNS.setDataNotSync(10);
was10Written = true;
}
public void insideAnotherThread() {
if(was10Written) {
int value = dataNS.getDataNotSync();
assert value == 10;
}
}
}
The answer is no, it is not guaranteed to be visible, but it could be. Since the write of 10 is not synchronized there is no happens before ordering with respect to the synchronized read.
According to the java memory model "changes to fields made by one thread are guaranteed to be visible to other threads only under some conditions.
This is true if the writes of one thread happens before a synchronization action. The write to 10 happens after and as such there is no visibility guarantees.
If, for example, you have a new field and write to it as 10 before you write to dataSync
(synchronized), and you evaluate dataSync to be 45, then that write to the new field will be visible.