How does synchronized achieve visibility?

problem description

how does synchronized achieve visibility? after I added an empty Synchronize code block to thread B, thread B can correctly read that the value of I is 1, achieving visibility. Thread B will not stop without Synchronize code block. But even if an empty Synchronize code block is added, thread A should only execute iThread from main memory after executing Synchronize code block after locking, but I don"t think thread A has flushed iThread 1 from working memory to main memory yet, why this Synchronize code block can achieve I visibility.

related codes

public class b {

public static int i;
public static void main(String[] args) throws Exception {
    Object o = new Object();
    new Thread(() -> {             //A
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        i = 1;
        while (true) {
        }
    }).start();
    new Thread(() -> {            //B
        while (true) {
            synchronized (o) {   //B
            }
            if (i == 1) {
                System.out.println("");
                break;
            }
        }
    }).start();
}

}

topic description

sources of topics and their own ideas

related codes

/ / Please paste the code text below (do not replace the code with pictures)

what result do you expect? What is the error message actually seen?

Jan.28,2022

first of all, in terms of definition: JMM's two semantic rules about synchronized:
before a thread is unlocked, the latest value of the shared variable must be refreshed to the main memory
before the thread is locked, the value of the shared variable in the working memory will be emptied, so that the latest value needs to be reread from the main memory when using the shared variable

.

in implementation: the visibility of both locks and volatile is achieved through Barrier (Memnory Barrier) in memory

Menu