java内存模型

简介: java内存模型

CPU工作原理:



  1. 单核CPU工作原理-高速缓存:


image.png


(1)cpu读取数据时按照L1,L2,L3,物理内存的顺序依次查找


(2)L1,L2,L3的速度依次递减,容量依次递增


2.多核CPU工作原理-高速缓存:


image.png


并发编程问题:



  1. 缓存一致性问题:多核多线程并行执行导致L1,L2缓存数据不一致


image.png


1.举个例子:


image.png


结果分析:


image.png


编译器优化和指令重排:



image.png


上述1属于编译器重排序,2,3属于处理器重排序。重排序会导致多线程程序出现内存可见性问题。


举个例子-重排序:执行完成后 i = 1或者0


public class CpuReOrder {
    private int a = 0;
    private boolean flag = false;
    public void write(){
        a = 1;          //1
        flag = true;    //2
    }
    public void read(){
        if(flag){       //3
            int i = a; //4
            System.out.println(i);
        }
    }
    public static void main(String[] args){
        final CpuReOrder cpuReOrder = new CpuReOrder();
        //写线程
        new Thread(()->cpuReOrder.write()).start();
        //读线程
        new Thread(()->cpuReOrder.read()).start();
    }
}


java内存模型



  1. 重排序-数据依赖性:


image.png


image.png


2.As-if-serial:


image.png


并发编程的问题:



  1. 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。


(1)x=10; y=x; x++; x=x+1;x=new x(); 哪些操作具有原子性?


2.可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。(volatile,锁)


3.有序性即程序执行的顺序按照代码的先后顺序执行。(happens-before)


原子性、可见性、有序性是一个抽象的概念。其底层问题就是前面提到的硬件层面的缓存一致性问题、处理器优化问题和指令重排问题。


缓存一致性问题其实就是可见性问题。而处理器优化是可以导致原子性问题的(指令优化执行)。指令重排即会导致有序性问题。


举个例子:执行结束后:count=?


image.png


内存模型



1.算机内存模型为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操作行为的规范。通过这些规则来规范对内存的读写操作,从而保证指令执行的正确性。它与处理器有关、与缓存有关、与并发有关、与编译器也有关。它解决了CPU多级缓存、处理器优化、指令重排等导致的内存访问问题,保证了并发场景下的一致性、原子性和有序性。


2.内存屏障:每个CPU都会有自己的缓存(有的甚至L1,L2,L3),缓存的目的就是为了提高性能,避免每次都要向内存取。但是这样的弊端也很明显:不能实时的和内存发生信息交换,分在不同CPU执行的不同线程对同一个变量的缓存值不同。用volatile关键字修饰变量可以解决上述问题,那么volatile是如何做到这一点的呢?那就是内存屏障,内存屏障是硬件层的概念,不同的硬件平台实现内存屏障的手段并不是一样,java通过屏蔽这些差异,统一由jvm来生成内存屏障的指令。


(1)硬件层的内存屏障分为两种:Load Barrier 和 Store Barrier即读屏障和写屏障。内存屏障有两个作用:阻止屏障两侧的指令重排序;强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效。


(2)对于Load Barrier来说,在指令前插入Load Barrier,可以让高速缓存中的数据失效,强制重新从主内存加载数据;对于Store Barrier来说,在指令后插入Store Barrier,能让写入缓存中的最新数据更新写入主内存, 让其他线程可见。


3.**java内存屏障:**java的内存屏障通常所谓的四种即LoadLoad,StoreStore,LoadStore,StoreLoad实际上也是Load,store两种的组合,完成一系列的屏障和数据同步功能。


(1)LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。


(2)StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。


(3)LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。


(4)StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。 它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。


4.数据竞争


image.png


5.顺序一致性内存模型:


image.png


6.顺序一致性模型中程序执行示意图


image.png


正确同步的程序:


image.png


JMM与顺序一致性模型执行效果对比:


image.png


7.**happens before规则:**在JMM中要保证一个操作的结果对另一个操作可见,那么这两个操作(可能是多个线程)之间要存在happens-before关系。


如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。


两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens- before关系指定的顺序来执行。如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么这种重排序并不非法(也就是说,JMM允许这种重排序)


8.happens-before 具体规则:


(1)程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续的操作。


(2)监视器锁的规则:锁的解锁happens-before随后对它的加锁。


(3)volatile变量的规则:对一个volatile域的写happens-before于任意后续对它的读。


(4)传递性:A happens-before B, B happens-before C,那么A happens-before C。


(5)start()规则:线程A执行操作ThreadB.start(),那么A线程的ThreadB.start()操作happens-before 于B线程的任意操作。这意味着:线程A在执行ThreadB.start()之前对共享变量所做的修改,在线程B执行后都将对B可见。


(6)join()规则:线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before 于线程A从ThreadB.join()操作成功返回。这意味着:线程A执行操作ThreadB.join()并成功返回后,线程B的任意操作都将对线程A可见。


举个例子:

image.png


image.png


9.Volatile内存语义总结:


image.png


10.Volatile内存语义实现-JMM针对编译器指定的重排序规则表


image.png


11.Volatile内存语义实现


image.png


image.png


12.锁的释放获取建立的happens-before原则


image.png


13.JMM的内存可见性保证


image.png





目录
相关文章
|
20小时前
|
安全 Java
解决Java中集合类的内存占用问题
解决Java中集合类的内存占用问题
|
1天前
|
存储 监控 算法
Java堆栈内存管理与优化技巧的实践指南
Java堆栈内存管理与优化技巧的实践指南
|
2天前
|
安全 Java 程序员
深入理解Java内存模型(JMM)及其对并发编程的影响
【6月更文挑战第29天】在Java并发编程的世界中,内存模型是基石之一。本文将深入探讨Java内存模型(JMM)的核心概念,包括可见性、原子性、有序性和同步,并解释它们如何影响并发编程实践。通过分析JMM的工作原理和它与Java并发库的关系,我们将揭示正确使用JMM原则可以如何避免并发编程中的常见陷阱。
|
2天前
|
存储 监控 算法
掌握Java内存管理:从入门到精通
【6月更文挑战第29天】本篇文章将引导读者深入理解Java的内存管理机制。不同于传统的技术文章,我们将通过一个故事来展开讲解,让复杂的技术内容变得生动易懂。文章不仅会涵盖基础的内存分配和回收概念,还将探讨高级特性如JVM调优和内存泄漏检测工具的使用,帮助开发者有效提升应用程序的性能和稳定性。
|
3天前
|
Java 程序员 编译器
Java内存模型深度解析与实践优化策略
在多线程编程领域,Java内存模型(Java Memory Model, JMM)是确保并发程序正确性的基石。本文深入探讨JMM的工作原理,结合最新研究成果和实际案例,揭示高效同步策略和避免常见并发缺陷的方法。文章不仅阐述理论,更注重实践,旨在为Java开发者提供全面的内存模型应用指南。
|
3天前
|
Java 程序员
深入理解Java内存模型(JMM)与并发编程
在Java并发编程领域,理解Java内存模型(JMM)是至关重要的。本文旨在通过数据导向的分析、科学严谨的论述和逻辑严密的结构,探讨JMM如何影响并发编程实践。我们将从JMM的基本概念出发,逐步深入到并发编程中的具体应用,包括同步机制、volatile关键字的作用以及线程间的通信。本文将引用权威研究与实验证据,结合经典理论,为读者提供全面的JMM知识框架,以促进对Java并发编程深层次的理解。
|
3天前
|
存储 安全 Java
Java内存模型:你需要知道的一切
Java内存模型:你需要知道的一切
|
3天前
|
Java
Java内存模型之原子性问题
Java内存模型之原子性问题
|
3天前
|
存储 缓存 Java
【Java并发基础】Java内存模型解决有序性和可见性
【Java并发基础】Java内存模型解决有序性和可见性
|
4天前
|
存储 缓存 Java
Java对象内存布局深度解析
Java对象内存布局深度解析
9 0