JMM作用和原理

目录

前言

CPU缓存模型

JMM

1、JMM的作用

2、谈JMM前的说明

3、JMM示意图

JMM有8种原子内存语义操作

1、8种原子内存语义的作用

2、8种原子语义有哪些

3、JMM的8中基本操作必须满足的规则

先行先发原则

1、先行先发原则的作用

2、先行先发原则的规则

3、happen before和JMM的关系

线程的三大特性

原子性

可见性

有序性

Jmm对线程三大特性的保障

volatile介绍

1、volatile内部原理

2、volatile的变量新增的内存语义

3、volatile作用


前言

  1. 多线程内存的划分分为:java线程、工作内存、save和load操作、主内存
  2. 编译器和执行器都会对指令进行重排。处理器通过内存屏障限制指令重排,编译器可以禁止特定类型的编译器进行指令重排。
  3. 指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致

CPU缓存模型

JMM

1、JMM的作用

定义一些规范,处理多线程间数据的通信;解决多线程环境下指令重排序导致的问题。

  • 用于屏蔽不同操作系统间的内存差异,线程和主内存之间的关系。8种原子性语义操作
  • 定义Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范。8种原子性语义操作
  • 定义了一些并发编程相关的规范来解决一些问题,开发者可以利用这些规范更方便地开发多线程程序。(如:抽象了 happens-before 原则来解决这个指令重排序问题)

2、谈JMM前的说明

  • JMM只是一个抽象内存模型。
  • JMM和物理机内存模型不是一个范畴。
  • JMM和Java运行时数据区没有直接对应关系。

3、JMM示意图

JMM有8种原子内存语义操作

1、8种原子内存语义的作用

用来描述线程本地内存和主动内存的交互协议,java线程之间的通信由JMM控制。

2、8种原子语义有哪些

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

2、unlock(解锁):作用于主内存的变量,它吧一个处于锁定状态的变量释放出来,释放后的变量才能被其它线程锁定。

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

4、load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入到工作内存的变量副本中。

5、assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量。

6、store(存储):作用于工作内存的变量,把工作内存的变量传到主内存中,以便随后write操作。

7、write(写入):作用于主内存的变量,把store操作从工作内存中的变量放到主内存中。

3、JMM的8中基本操作必须满足的规则

1、不允许read和load、store和write操作之一单独出现

2、发生过assign操作,必须把变量在工作内存改变后必须同步会主内存(同步的时间点不一定)

3、没有发生过assign操作,不允许把数据从工作内存同步回主内存

4、新变量只能从主内存诞生

5、一个变量同一时刻只允许一个线程对其进行lock操作,但可被同一线程多次lock,lock几次就要unlock几次(synchronized同步代码块原理实现方式)

6、一个变量执行lock操作会清空工作内存中该变量的值

7、变量没有执行lock操作则不能执行unlock操作

8、对变量执行unlock前,必须把此变量同步回主内存(synchronized同步块可见性实现原理)

注意:synchronized对线程原子性、可见行、有序性的保障,其实底层是通过8种基本操作实现的

先行先发原则

1、先行先发原则的作用

  • 为了程序员和编译器、处理器之间的平衡,只要不改变程序的执行结果,编译器和处理器怎么进行重排序优化都行。
  • 会改变程序执行结果的重排序,JMM 要求编译器和处理器必须禁止这种重排序
  • 表达的意义其实并不是一个操作发生在另外一个操作的前面,虽然这从程序员的角度上来说也并无大碍。更准确地来说,它更想表达的意义是前一个操作的结果对于后一个操作是可见的,无论这两个操作是否在同一个线程里。阐述操作之间的内存可见性。

  • 判断数据是否存在竞争,线程是否安全的依据。
  • JMM中的顺序性不能仅仅依靠volatile和synchronized.
  • 先行发生原则和时间的先后顺序没什么关系

2、先行先发原则的规则

A操作先行发生于B操作,那A操作的影响能被B操作观察到。(影响包括内存共享变量值的改变、发送消息、调用方法等)

1、程序次序:一个线程内,按照程序代码的顺序,写在前面的操作先行发生于后面的操作。

2、synchronized相关:unlock先于后面的lock

一个unlock操作先行发生于后面对同一个锁的lock操作。(后面只时间的先后)

3、volatile相关:写先于读

对volatile的写操作先行发生于后面对这个变量的读操作。(后面只时间的先后)

线程相关

4、start():Thread的start()方法先行发生于此线程的每一个动作。(start()先于所有动作)

5、join()或isAlive():线程中的所有操作先行发生于对此线程的终止检验(所有动作先于Thread.join方法结束、Thread.isAlive等)

6、interrupt():线程中断先行发生于对中断检验代码(interrupt()先于Thread.interrupted())

7、finalize():初始化方法的完成先于finalize()的开始

8、传递性:A操作先于B操作,B操作先于C操作,那A操作先于C操作。

3、happen before和JMM的关系

线程的三大特性

原子性

1、基本数据类型的访问读写是具备原子性的

2、lock和unlock操作没有开放个用户直接使用,但是提供了更高级别的字节码指令monitorenter和monitorexit,也就是java中的synchronized快

可见性

一个线程修改了某一个共享变量的值,其他线程是否能够立刻知道这个修改。

1、synchronized和final关键字也具有可见性

2、synchronized可见性是因为,对一个变量执行unlock前,必须先把变量同步回主内存中(执行store和write操作)这条获得的。

3、final可见性,被final修饰的字段在构造器中一旦初始化完成,其它线程就能看见该字段的值。

有序性

由于指令重排序问题,代码的执行顺序未必就是编写代码时候的顺序。

synchronized的有序性是通过 一个变量在同一时刻只允许一个线程对其进行lock操作 获得的。

Jmm对线程三大特性的保障

volatile介绍

1、volatile内部原理

volatile变量赋值后,汇编代码会多一个lock操作,相当于内存屏障,作用是使本CPU的缓存写入内存(相当于store和write操作),该写入动作会使其他cpu的缓存无效,所以valatile变量的修改对其它cpu立即可见。

2、volatile的变量新增的内存语义

1、工作内存中,每次使用使用对象前必须先从主内存刷新最新的值。(其它cpu能看到变量最新的值)

2、工作内存中,每次修改变量后必须立刻同步会主内存中。(其它线程可以看到本线程对变量的修改)

3、volatile修饰的变量不会被指令从排序优化。(a肯定在b之前执行)

volatile boolean a;

int i=3;

int j=5;

volatile boolean b;

3、volatile作用

1、只能保证变量对所有线程的可见性,不能保证原子性和有序性。

2、每次使用前,都要先刷新,执行引擎看不到不一致的情况,因此可以认为不存在一致性的问题。

3、使用Volatile变量会禁止指令重排序优化,其实就是内存屏障的作用,(volatile前的代码不会在volatile变量之后执行,volatile变量之后的代码也不会在volatile变量之前执行),保证代码的执行顺序与程序的顺序相同。

4、每次使用变量前必须从主内存刷新最新的值,每次修改变量后必须立刻同步回主内存中。

5、目前商用虚拟机几乎都把64位的数据读写操作作为原子操作来对待。

4、内存屏障

  • 内存屏障(memory barrier)是一个CPU指令。该指令确保一些特定操作执行的顺序,或者影响一些数据的可见性。
  • 编译器和CPU可以在保证输出结果一样的情况下对指令重排序,使性能得到优化。插入一个内存屏障,相当于告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行。
  • volatile通过插入内存屏障(Memory Barrier),在内存屏障前后禁止重排序优化,以此实现有序性。内存屏障有两个作用:一是保证特定操作的执行顺序,二是保证某些变量的内存可见性。

在这里插入图片描述 

 

参考:JMM(Java 内存模型)详解 | JavaGuide(Java面试+学习指南)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值