Java内存模型:
JMM数据原子操作:
具体操作步骤:
线程1:先把initFlag变量read读取出来,再load载入工作内存,use使用线程1执行代码!initFlag
线程2:先把initFlag变量read读取出来,再load载入工作内存,use使用线程2执行代码initFlag=true,再assign重新赋值,store存储并写入主内存,write写入到主内存中的变量。(线程2对缓存行lock加锁,write写入主内存后会解锁unlock,防止initFlag还未write写入主内存就被线程1读取为false)。
线程1:因为initFlag被volatile修饰,使用MESI缓存一致性协议,线程1cpu总线嗅探机制监听到了initFlag值的修改,线程1中initFlag=false失效变为true退出循环继续执行,体现了多线程同步运行共享变量副本的可见性。如果initFlag没有被volatile修饰,线程1将感知不到initFlag的变化,一直循环下去停止不了。
图中的代码:
public class VolatileVisibilityTest {
//volatile变量,用来确保将变量的更新操作通知到其他线程。
private static volatile boolean initFlag = false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("waiting data...");
while (!initFlag) {
}
System.out.println("==============success");
}
}).start();
Thread.sleep(2000);
new Thread(new Runnable() {
@Override
public void run() {
prepareData();
}
}).start();
}
public static void prepareData(){
System.out.println("preparing data...");
initFlag = true;
System.out.println("prepare data end...");
}
}
解决jmm缓存不一致问题:
总线加锁:
lock和unlock会对主内存加锁的,总线加锁一般不使用,效率太低,跟单线程差不多。一般用MESI缓存一致性协议。