Java 的内存模型怎么理解呢?

 2019-12-10 16:11  阅读(958)
文章分类:Java Core

JMM memory model:是jvm在(RAM)中的工作方式。JMM 属于JVM.

理解JMM是理解并发编程的前提。并发编程中三大特征:

  1. 原子性:原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行.
  2. 可见性:可见性就是指当一个线程修改了线程共享变量的值,其它线程能够立即得知这个修改.
  3. 有序性:有序性即程序执行的顺序按照代码的先后顺序执行。

并发:线程之间的通信!很重要。

共享内存(线程之间共享的程序的公共状态,synchronized可以通过共享对象进行通信。read write内存可以达到隐式通信的目的)同步关键字,while轮询(浪费CPU)

消息传递(这中情况下,线程没有公共状态,必须彼此间发送明确的消息,显式通信。典型的 wait()notify()等)

线程同步怎么实现的? 同步就是一件事,一件事情一件事的做。 异步就是,做一件事情,不引响做其他事情。

共享内存的并发模型中:显式实现,coder显式指定某个方法或者某段代码需要线程互斥。

消息传递的模型中:消息发送必须在消息接收之前。同步是隐式的。

java的并发实现的是共享内存(JMM)的模型。Java线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。

JMM定义了线程和主内存之间的抽象关系。

线程之间的共享变量 — 是在主内存中的,每个线程都有一个私有的private的本地内存,存储了该线程 read/write共享变量的副本。本地内存是一个抽象的概念,不存在的。

20191210001644\_1.png

A和B要想通信,必须1.A把本地内存中更新的变量刷新到主内存中。

2.B从主内存读取A更新过得共享变量。

JVM的存储模型中 ,java堆和方法区 都是线程共享的区域。

由此引发了问题:

1.共享对象 对 各个线程的可见性。

2.共享对象的竞争。

1.可见性这个,之前看过,volatile变量就是可以解决可见性。使得一个线程对共享对象的修改对其他线程是可见的。

CPU执行的时候,线程会把对象从主内存中 copy到它的CPU缓冲。

2.如果共享对象了,那么大家同时修改这个对象,出现的竞争该怎么解决?串行化,使用同步代码块 synchronized关键字。

volatile和synchronized的区别

  1. volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取,缓存不靠谱,同时一旦修改立刻flush到主存; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  2. volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  3. volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  4. volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  5. volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

Java JMM的基础原理:

指令重排序

  1. 编译器优化重排序:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  2. 指令级并行的重排序:如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
  3. 内存系统的重排序:处理器使用缓存和读写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

数据依赖性

如果两个操作访问同一个变量,其中一个为写操作,此时这两个操作之间存在数据依赖性。

编译器和处理器不会改变存在数据依赖性关系的两个操作的执行顺序,即不会重排序。

as-if-serial

不管怎么重排序,单线程下的执行结果不能被改变,编译器、runtime和处理器都必须遵守as-if-serial语义。

内存屏障(Memory Barrier )

上面讲到了,通过内存屏障可以禁止特定类型处理器的重排序,从而让程序按我们预想的流程去执行。内存屏障,又称内存栅栏,是一个CPU指令,基本上它是一条这样的指令:

  1. 保证特定操作的执行顺序。
  2. 影响某些数据(或则是某条指令的执行结果)的内存可见性。

转载参考自:https://blog.csdn.net/suifeng3051/article/details/52611310

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Java 的内存模型怎么理解呢?

相关推荐