Java并发编程:Java内存模型JMM

简介

Java内存模型英文叫作(Java Memory Model),简称为JMM。Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各类硬件和系统的内存访问差别,实现平台无关性。java

CPU和缓存一致性

讲JMM以前,咱们应该先了解下CPU和缓存一致性的问题。计算机在执行程序的时候,每条指令都是在CPU中执行的,而执行的时候,又要和数据打交道。而计算机上面的数据,是存放在内存当中的。随着CPU的高速发展,从内存中读取和写入数据的过程和CPU的执行速度比起来差距就会愈来愈大,这致使了CPU不能满负荷的工做,须要去等待数据从内存中读取或者写入。缓存

为了解决内存和CPU速度不一致的问题,继而引入了高速缓存这么一个东西。在CPU和内存之间,放一个高速缓存做为缓冲,这样一来就提高了CPU的读写速度。安全

高速缓存解决了处理器和内存速度的矛盾,可是却引入了另一个复杂的问题——缓存一致性。在多处理器系统中,每一个处理器都有本身的高速缓存,而内存又是各处理器共享的,这就可能致使各自的缓存数据不一致的状况。多线程

为了解决缓存一致性的问题,各个处理器访问缓存时都遵循必定的协议,在读写时根据协议来操做,进而保证缓存的一致性。为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操做行为的规范。并发

Java内存模型(JMM)

Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各类硬件和系统的内存访问差别,实现平台无关性。其底层是根据不一样系统的缓存读写协议分别进行处理的。开发者不用去关心各系统的差别,由于JVM已经帮咱们屏蔽了各系统的细节差别,咱们只须要关注JMM便可。spa

Java内存模型就是一种符合内存模型规范的,屏蔽了各类硬件和操做系统的访问差别的,保证了Java程序在各类平台下对内存的访问都能保证效果一致的机制及规范。操作系统

Java内存模型定义了线程和主内存之间的抽象关系,Java各线程之间的通讯是有Java内存模型所控制的。从抽象来说,线程之间的共享变量存储在主内存(main memory)中,每一个线程都有一个私有的工做内存(本地内存)(local memory),本地内存中存储了该线程以读 / 写共享变量的副本。线程

Java内存模型里所说的主内存,和工做内存(本地内存),都是抽象的概念,真实是不存在的,要区别于CPU高速缓存和内存设备。JMM只是JVM为了屏蔽系统内存操做的差别所抽象出来的概念。code

主内存和工做内存(本地内存)

img

Java内存模型规定了全部的变量都在主内存中,每条线程都有本身的工做内存。Java线程工做的时候,从主内存load数据到本身的工做内存中,这时工做内存就持有了主内存的一份数据拷贝。线程操做完以后,把数据从新save回主内存中。cdn

线程安全问题

理解Java内存模型,是理解线程安全问题的基础。知道JMM有主内存和工做内存之分以后,咱们就很容易的理解多个线程操做同个共享变量可能引起的数据不一致的问题。假设有以下代码:

public class Main {

    private static int a = 0;

    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                a = a+1;
            }).start();
        }

        Thread.sleep(3000);

        System.out.println(a);

    }

}
复制代码

这里有一万个线程去操做共享数据a,若是不存在并发问题的话,“预期的结果应该是10000”。执行程序,结果:

结果一:

结果二:

结果三:

实际的结果是无法预测的,理解了上面主内存和工做内存之分以后,相信你很快能理解其中的缘由。假设a等于0,同时存在两个线程对其作了++操做,这时两个工做内存的a都是1,回写到主内存的时候也是1,“至关于少了一个1了”。

总结

本文介绍了Java的内存模型,这里须要强调的一点是,Java内存模型不一样于Java内存结构,不要将两者概念混淆。Java内存模型是为了解决各线程之间的通讯所抽象出来的概念,Java内存结构则是Java中的数据存储形式,也就是常常提到的堆内存、栈内存等。

相关文章
相关标签/搜索