JMM(Java Memory Model,Java内存模型)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42220174/article/details/100765297

JMM(Java内存模型)

“内存模型”可以理解为在特定的操作协议下,对特定的内存或高速缓存进行读写访问的过程抽象。Java 内存模型(JMM)是一种抽象的概念,并不真实存在,它描述了一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段、静态字段和构成数组对象的元素)的访问方式。Java内存模型主要是为了屏蔽掉各种硬件和操作系统的内存访问差异,以实现Java的“一次编译、到处运行”的效果。Java内存模型的抽象图如下:
在这里插入图片描述
      JMM规定了所有的变量都存储在主内存中,而JVM运行的实体是线程,每条线程有自己的工作内存,线程对变量的所有操作都必须在自己的工作内存中进行,而不能直接读写主内存中的变量,线程中存储的是该线程用到的主内存变量的副本拷贝。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要通过主内存来完成。

JMM关于同步的规定

  • 线程加锁前,必须将共享变量值读取到自己的工作内存;
  • 线程解锁前,必须将共享变量的值刷新回主内存;
  • 加锁解锁是同一把锁

内存模型三大特性(重点)

  • 原子性:与事务的原子性一致,原子性通常指多个操作不存在只执行一部分的情况,必须全部执行。JMM直接保证的原子性变量操作:read、load、assign、use、store、write、lock、unlock

  • 可见性当一个线程修改了主内存共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。JMM 内部的实现通常是依赖于所谓的内存屏障 ,通过禁止指令重排序的方式,提供内存可见性保证 。主要有有三种实现可见性的方式:

    • volatile:修改了volatile类型的变量之后,JMM会强制将变量值同步回主存 。
    • synchronized:对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
    • final:被final修饰的字段在构造器中一旦初始化完成,那在其他线程中就可以看见final字段的值。
  • 有序性:在本线程内观察,所有操作都是有序的。在一个线程观察另一个线程,所有操作都是无序的,无序是因为发生了指令重排序。在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
    实现有序性的两种方式:

    • volatile :通过添加内存屏障的方式来禁止指令重排,即重排序时不能把后面的指令放到内存屏障之前。
    • synchronized:它保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码(synchronized的实现原理:Synchronized的语义底层是通过一个monitor的对象来完成,monitorenter和moniterexit指令)。

volatile

volatile具有两个特性:

  • 保证变量对所有线程的可见性:可见性是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的,而普通变量无法做到这点。但是并不能保证原子性,如果Java里的运算是非原子操作,导致volatile变量的运算在并发下是不安全的。即volatile只能保证可见性,不能保证原子性。
  • 禁止指令重排序:通过设置内存屏障实现,指令重排序时不能把后面的指令重排序到内存屏障之前的位置。

synchronized

synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。synchronized的实现原理:synchronized的语义底层是通过一个monitor的对象来完成,包含monitorenter和moniterexit指令。

猜你喜欢

转载自blog.csdn.net/qq_42220174/article/details/100765297