一、volatile 关键字解决问题
1.共享变量可见性问题
package thread.threadpool;
public class volatileTest {
private static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("waiting data...");
while (!flag){
}
System.out.println("===========finished===========");
}
}).start();
Thread.sleep(2000);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("马上修改flag值");
flag=true;
System.out.println("修改完成flag值");
}
}).start();
}
}
结果如下图,而且不停止,即程序不跳出while循环
2.解释原因
当一个线程读取主内存后,先放入线程本地缓存,然后运算。上面的原因是当线程1进入while循环后,是一直读取线程1本地的缓存;而线程2修改flag值后,是写入到主内存中,但是线程1读取不到主内存中的更新值。
3.修改:添加volatile关键字修饰共享变量
package thread.threadpool;
public class volatileTest {
private volatile static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("waiting data...");
while (!flag){
}
System.out.println("===========finished===========");
}
}).start();
Thread.sleep(2000);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("马上修改flag值");
flag=true;
System.out.println("修改完成flag值");
}
}).start();
}
}
结果:
4.volatile 关键字作用
volatile关键字,针对共享变量的实现了MESI缓存一致性协议。
即:多个cpu从主内存读取同一个共享数据到各自的高速缓存,当其中某个cpu修改了缓存里的数据,该数据会马上同步回主内存。同时,其它cpu通过总线嗅探机制可以感知到数据(flag)的变化,从而将自己线程缓存里的数据失效,当线程再需要该变量则从主内存中重新读取。
二、JMM原子操作
- read(读取):从主内存读取数据
- load(载入):将主内存读取到的数据写入工作内存
- use(使用):从工作内存读取数据来计算
- assign(赋值):将计算好的值重新赋值到工作内存中
- store(存储):将工作内存数据写入主内存
- write(写入):将store过去的变量值赋值给主内存中的变量
- lock(锁定):将主内存变量加锁,标识为线程独占状态
- unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量
三、参考
1.再有人问你Java内存模型是什么,就把这篇文章发给他。
https://blog.csdn.net/hollis_chuang/article/details/80880118
2.https://www.bilibili.com/video/av59871562?p=2