Java内存模型JMM

目录

什么是JMM

JMM的同步规定

JMM模型的八种指令操作

JMM的八种指令使用规则

不使用volatile操作JMM发生的问题


 

什么是JMM

 

JMM:是Java Memory Model的缩写,即java内存模型。这个内存模型是抽象上的概念~

JMM定义了线程工作(子)内存和主内存之间的抽象关系:即线程之间的共享变量存储在主内存(Main Memory),每个子线程都有一个私有的本地内存(Local Memory)

基于JMM的操作要保证可见性、原子性、有序性(禁止指令重排)

 

 

JMM的同步规定

 

JMM实现同步操作有如下3条规定

1.线程解锁前,必须把共享变量立刻刷会主存

2.线程加锁前,必须读取主存中的最新值到工作内存中

3.加锁和解锁必须是同一把锁

 

 

JMM模型的八种指令操作

 

1.lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态

2.unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

3.read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用

4.load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中

5.use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令

6.assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中

7.store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用

8.write (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

子线程(工作线程)执行时,并不是直接操作主线程的数据,而是先copy一份,然后对这份copy的进行操作,操作完毕再存储到主线程 

内存交互的八种操作在工作时,必须保证每一对操作是原子性的不可分割的(对于double和long类型的变量来说,load、stroe、read、write操作在某些平台上允许例外)

 

 

JMM的八种指令使用规则

 

1.不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了stroe必须write

2.不允许线程丢弃它最近的assign操作,即工作变量的数据改变之后,必须告知主存

3.不允许一个线程将没有assign的数据从工作内存同步回主内存

4.一个新变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是对变量事实use、store操作前,必须经过assign和load操作

5.一个变量同一时间只有一个线程能对其进行lock,多次lock后必须执行相同次数的unlock才能解锁

6.如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重写load或assign操作初始化变量的值

7.如果一个变量没有被lock,就不能对其进行unlock操作,也不能unlock一个被其他线程锁住的变量

8.对一个变量进行unlock之前,必须把此变量同步回主内存

 

总结:JMM的八种操作和对volatile的使用就能确定哪些操作是线程安全的,哪些操作是线程不安全的。

 

 

不使用volatile操作JMM发生的问题

 

我们搞个小例子,开辟一个子线程,只要子线程检测到静态变量为0,就让它一直执行下去。

public class JMMDemo {
    private static int num = 0;

    public static void main(String[] args) {
        new Thread(()->{
            while (num ==0){

            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        num = 1;
        System.out.println(num);
    }
}

在让num的值变为1之前,我让主线程睡了1s。主线程醒了之后,num的值变成1,但是子线程却停不下来了。这是为什么呢? 

主线程和子线程之间是独立运行的,假如让主线程睡眠1s,子线程无法感知到主线程做了什么。就好比,一列火车刚开始只有主线程一节车厢,后来新加了一个子线程车厢,当主线程睡眠哪怕就1秒时,主线程和子线程之间的连接也断开了。当主线程醒了之后,子线程车厢和主线程车厢分离了。无论主线程再进行什么操作,子线程都无法感知,依然自顾自的走。因为子线程是拿着之前copy主线程的数据走,而没有进行最新copy的操作。

 

这个问题说明什么?多线程操作后,每个子线程的值分别store给主线程,但彼此却不知道主线程每时每刻的变化,主线程的值出现了覆盖现象,子线程的操作出现了之后线程,这可就乱了套了

因此多线程在操作内存时,一定是加了同步操作。那它使用了什么呢?答案是volilate。关于volilate是如何来解决线程同步问题的,我们将在下一篇博客来讲~

https://blog.csdn.net/Delicious_Life/article/details/106497301

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值