JMM内存模型详解

JMM(Java Memory Model)内存模型详解

java线程内存模型跟CPU缓存模型类似,是基于cpu缓存模型建立的,Java线程内存模型是标准化的,屏蔽掉了底层不同计算机的区别.

CPU缓存模型

在这里插入图片描述

JMM在这里插入图片描述


证明工作内存的存在

public class JMM {
    public static boolean initFlag = false;
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread1 开始.....");
                while(!initFlag){
                }
                System.out.println("initFlag == true");
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2开始...");
                change();
            }
        }).start();
    }

    private static void change() {
        initFlag = true;
        System.out.println("已将initFlag改为true.....");
    }
}

我们本来想的是,第二个线程把initFlag改为true后,第一个线程跳出循环,并打印initFlag == true;我们看看运行结果
在这里插入图片描述
我们惊喜的发现,似乎线程1中的initFlag并没有该成true,还在死循环中,由此可见,线程2更改的值并没有对线程1造成影响,由此可以证明,工作内存的存在,各个工作内存是相互独立的


但是,我们想要的结果是跳出循环,那么我们就可以对共享变量加volatile关键字

public static volatile boolean initFlag = false;

在这里插入图片描述


JMM数据原子操作

  • read (读取) : 从主内存读取数据
  • load (载入) : 将主内存读取到的数据写入工作内存
  • use (使用) : 从工作内存读取数据来计算
  • assign (赋值) : 将计算好的值重新赋值到工作内存中
  • store (存储) : 将工作内存的数据写入主内存
  • write (写入) : 将store过去的变量值赋予给主内存中的变量
  • lock (锁定) : 将主内存变量加锁,标识为线程独占状态
  • unlock(解锁) : 将主内存变量解锁,解锁后的其他线程可以锁定该变量

(无volatile过程)

先看前四个原子操作的流程(无volatile)

在这里插入图片描述
目前到assign (赋值)操作之后,工作内存中的值更改


store和write

在这里插入图片描述


加上volatile后

但这样会出现缓存不一致现象,怎样解决

  • 总线枷锁(性能太低)

    • cpu从主内存读取数据到高速缓存,会在总线对这个数据加锁,这样其他cpu无法去读写这个数据,直到这个cpu使用完数据释放锁之后,其他cpu才能读取该数据
      在这里插入图片描述
  • MESI缓存一致性协议

    • 多个cpu从主内存读取同一个数据到各自高速缓存,其中某个cpu修改了缓存里的数据,该数据会马上同步到主内存,其他cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失败
      在这里插入图片描述
  • 假如现在有CPU2和CPU1,主内存有变量initFlag = false 。现在cpu2要做 initFlag = true的操作。

  • 如果在变量 initFlag = false 上加上volatile,则就会触发MESI

  • 当CPU1从主内存中读取到initFlag = false时,CPU1会把此变量标记成独享状态

  • 并监听总线,是否有其它CPU去读取此变量

  • 当CPU2从主内存中读取initFlag = false变量时,CPU1会通过嗅探机制监听到。

  • 此时CPU2的initFlag变量会变成共享状态。继续进行赋值,赋值完变成initFlag = true

  • 此时要回写到主内存之前。先锁住缓存行。并标记initFlag变量为修改状态。并向总线发消息。

  • CPU1监听总线时,会监听到,并把initFlag标记成无效状态。

  • CPU2把变量initFlag = true回写到主内存后,会由修改状态变成独享状态。

  • 此时,如果CPU1如果想修改X变量时,要重启从主内存中读取。然后开始新的轮回。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值