I am reading 《Understanding the JVM Advanced Features and Best practices》 that has a code segment that explains happens-before rule in java. I cannot understand. The code is below:
private int value = 0;
//executed by Thread A
public void setValue(int value){
this.value = value;
}
//executed by Thread B
public void getValue(){
return value;
}
Suppose that thread A
starts before thread B
in code. I can understand that we don't know the result returned by getValue()
in Thread B, because it is not thread safe. But the book says if add synchronized key word to function setValue()
and getValue()
, then there is not exists thread safe problem and method getValue()
will return the right value. The book explains that because synchronized
meets with happens-before rule. So I have two questions by below code.
public class VolatileDemo3 {
private volatile int value = 0;
public static void main(String[] args) {
VolatileDemo3 v = new VolatileDemo3();
Thread A = new Thread(v.new Test1());// Thread A
Thread B = new Thread(v.new Test2());//Thread B
A.start();
B.start();
}
public void setValue(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
public class Test1 implements Runnable {
@Override
public void run() {
setValue(10);
}
}
public class Test2 implements Runnable {
@Override
public void run() {
int v = getValue();
System.out.println(v);
}
}
}
A.start()
run before B.start()
and value is volatile
, we can't ensure thread B can print out 10
, right? Because thread B is possible scheduled first by JVM, then thread B will print 0 not 10.A
scheduled before thread B
by JVM, but we also can't guarantee that the instruction this.value = value
executed by JVM before return this.value
because JVM will sort instructions again. Am I understanding is right? Please help me.The issue of "happened before" is not that it causes thread A to set the value before thread B. It is that although it may happen that thread A got to the this.value = value
chronologically before thread B got to run getValue
, the value B sees may still be the old value.
That is, in a threaded environment, even if two instructions are performed in chronological order, it doesn't mean that the results of one will be seen by the other.
If thread B happened to call the method first, it will always get the old value. But if it happened to call the method second, it's unknown if it gets the old or the new value.
For this reason, you have to use means to ensure the "happens before" rule, and then you know that the results of what "happened before" are seen by what "happens after".
So if value
is volatile, for example, it ensures that if setValue()
is called by thread A before thread B, then thread B will see the new value.
╔═════════════════════╤════════════════════════╤═════════════════════╗ ║ Order of operations │ Are we using │ What value of value ║ ║ │ volatile/synchronized? │ will B see? ║ ╠═════════════════════╪════════════════════════╪═════════════════════╣ ║ A runs setValue(10) │ N │ Unknown ║ ║ B runs getValue() ├────────────────────────┼─────────────────────╢ ║ │ Y │ 10 ║ ╟─────────────────────┼────────────────────────┼─────────────────────╢ ║ B runs getValue() │ N │ 0 ║ ║ A runs setValue(10) ├────────────────────────┼─────────────────────╢ ║ │ Y │ 0 ║ ╚═════════════════════╧════════════════════════╧═════════════════════╝
Regarding your two questions:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With