Please see the code below:
private static boolean flag=true; // main thread will call flag=false
private final static Object lock=new Object(); // lock condition
public static void thread1(){
while (flag){
synchronized (lock){
// some work
}
}
}
public static void main(String[] args) throws Exception {
Thread t1=new Thread(()->{
thread1();
});
t1.start();
Thread.sleep(1000);
flag=false;
// The program can stop normally
}
No matter at any time , When one thread entering the synchronized block, will the value of the variable flag be loaded from main memory?
Thank you for your detailed explanation, because I am not sure if the flag has a happend-befores relationship. Literally, the flag is not in the synchronized block.
Update1:
I know that using volatile can and I also know how to write the right code,, but I want to know now if there is no volatile keyword. Whether synchronized can guarantee visibility. Note: the flag variable is not in synchronized block.
Update2:
I updated the code again, the code on my win10+JDK8 system can stop normally, do you think it is correct or accidental, because it is not tested on all hardware systems, so I need theory to guide。
Focus on the question:
whether the loop condition (flag variable) has a happen-before relationship with the synchroized block inside the loop,If it has a happen-before relationship, jvm whether ensure that the flag variable is loaded from main memory even if the flag variable is not in the synchronized block.
If every one think there is no happen-before relationship, then how do you explain that when I remove the synchronized block, the code will loop indefinitely. When I add it, it will stop normally. Is this just an accident?
Thanks to the information provided by @xTrollxDudex and @markspace ,The code in the loop section is observed from the jvm level, If there is no happens-before relationship and the code may be optimized from :
while (flag){
synchronized (lock){
// some work
}
}
to :
if(flag){
while (true){
synchronized (lock){
//some work
}
}
}
To ensure thread visibility, we need to avoid this optimization, such as through the volatile keyword or other synchronization strategies. The appearance of the sync block in the loop is similar to the function of the enhanced volatile keyword, which guarantees the visibility of the variable in front of it, so when we loop into the sync block for the second time, we can see it latest. The change, which is why the loop can stop normally. It looks fine, but it's not the right synchronization method, so don't do it.
For a detailed explanation, please see a similar question in here