synchronized的内存可见性很垃圾,慎用,也给了大家一个提醒,synchronized主要是用来互斥,内存可见性尽量用volatile保持
例子
public class TestSyncMemorySee {
static boolean r=false;
static Object o=new Object();
public static void main(String[] args) {
Thread t1=new Thread(()->{
synchronized (o){
while (!r){}
}
System.out.println(Thread.currentThread().getName()+"end");
},"t1");
Thread t2=new Thread(()->{
r=true;
System.out.println(Thread.currentThread().getName()+"end");
},"t2");
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
上面代码t1线程先开始执行,按照synchoinzed的内存可见性,获取锁后会刷新工作内存,从主内存拉取共享变量r=false,后面这个值是不会改变的,就算t2线程在1秒后改变了r=true,但是t1线程还在傻循环,由此可以推测synchronized的内存可见性只限于一次读取,解决办法是r变量加volatile修饰,volatile的内存可见性是无论什么时候读都是通过刷新工作内存,从主内存读取,底层是通过总线锁实现,汇编指令是lock。synchorinzed保持内存可见性底层还不太清楚,推测是简单的一次刷新工作内存,没有在cpu加锁