简介

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

CPU和缓存一致性

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

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

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

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

Java内存模型(JMM)

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

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

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

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

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

Java内存模型规定了所有的变量都在主内存中,每条线程都有自己的工作内存。Java线程工作的时候,从主内存load数据到自己的工作内存中,这时工作内存就持有了主内存的一份数据拷贝。线程操作完之后,把数据重新save回主内存中。

线程安全问题

理解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中的数据存储形式,也就是经常提到的堆内存、栈内存等。

Java并发编程:Java内存模型JMM的更多相关文章

  1. Java并发编程、内存模型与Volatile

    http://www.importnew.com/24082.html  volatile关键字 http://www.importnew.com/16142.html  ConcurrentHash ...

  2. Java并发编程-Java内存模型

    JVM内存结构与Java内存模型经常会混淆在一起,本文将对Java内存模型进行详细说明,并解释Java内存模型在线程通信方面起到的作用. 我们常说的JVM内存模式指的是JVM的内存分区:而Java内存 ...

  3. 高并发第二弹:并发概念及内存模型(JMM)

    高并发第二弹:并发概念及内存模型(JMM) 感谢 : 深入Java内存模型 http://www.importnew.com/10589.html, cpu缓存一致性 https://www.cnbl ...

  4. x86-TSO : 适用于x86体系架构并发编程的内存模型

    Abstract : 如今大数据,云计算,分布式系统等对算力要求高的方向如火如荼.提升计算机算力的一个低成本方法是增加CPU核心,而不是提高单个硬件工作效率. 这就要求软件开发者们能准确,熟悉地运用高 ...

  5. 【并发编程】- 内存模型(针对JSR-133内存模型)篇

    并发编程模型 1.两个关键问题 1)线程之间如何通信 共享内存 程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信 消息传递 程之间没有公共状态,线程之间必须通过发送消息来显式进行通信 ...

  6. Java并发编程:Java Thread 的 sleep() 和 wait() 的区别

      1. start 和 run 方法解释: 1) start: 用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码.通过调用Thread类 ...

  7. Java并发编程:Java Thread 的 run() 与 start() 的区别

    1. sleep 和 wait 方法解释 sleep()方法是Thread类里面的,主要的意义就是让当前线程停止执行,让出cpu给其他的线程,但是不会释放对象锁资源以及监控的状态,当指定的时间到了之后 ...

  8. Java并发编程:Java Thread方法join的简单总结

    虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结. 一.作用 Thread类中的join方法的主要作用就是同步,它可以使得线程之间 ...

  9. 《Java并发编程的艺术》笔记

    第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种:无锁并发编程.CAS算法.使用最少线程.使 ...

  10. java并发编程资料

    并发这玩意很有用,把自己在网上看过觉得总结的很好的资料分享出来.猛击下面的地址查看吧 java并发编程:线程池的使用说明 java并发编程系列文章 Java并发性和多线程专题 并发工具类 Java 7 ...

随机推荐

  1. 具体的client-server通信模型以及最为常用的通信模式

    实现虚拟网络服务的主要技术,指出IP负载均衡技术是在负载调度器的实现技术中效率最高的. 在已有的IP负载均衡技术中: 1)有通过网络地址转换(Network Address Translation)将 ...

  2. 图解 Kafka 水印备份机制

    高可用是很多分布式系统中必备的特征之一,Kafka 日志的高可用是通过基于 leader-follower 的多副本同步实现的,每个分区下有多个副本,其中只有一个是 leader 副本,提供发送和消费 ...

  3. Python - 协议和鸭子类型

    参考: Fluent_Python - P430 wiki 这里说的协议是什么?是让Python这种动态类型语言实现多态的方式. 在面向对象编程中,协议是非正式的接口,是一组方法,但只是一种文档,语言 ...

  4. ln N! -> N(lnN -1)

  5. 《如何写好商业计划书》---创业学习---训练营第三课---HHR---

    一,<开始上课> 1,投资人不愿意约见的原因:创始人没有把项目的投资价值和亮点呈现在商业计划书里. 2,BP的三个常见的错误:不够完整,关键内容没有呈现出来:华而不实:篇幅过长. 3,预热 ...

  6. Bugku-CTF加密篇之ok(Ook!)

  7. 在Linux系统中使用ntfs、fat32格式的存储设备

    在Linux系统中使用ntfs.fat32格式的存储设备   我们通常使用的移动硬盘或U盘一般都是ntfs或fat32的文件系统,作为一名运维工程师,经常会遇到把移动硬盘或者U盘上的内容拷贝的Linu ...

  8. dfs & bfs总结

    dfs 最简单的三种形式递归总结 bfs 百度https://baike.baidu.com/item/%E5%AE%BD%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7 ...

  9. git合并分支到master上面

    转自:https://www.cnblogs.com/mafeng/p/10173919.html 假如我们现在在dev分支上,刚开发完项目,执行了下列命令 git add .git commit - ...

  10. Spring学习(十)

    需要的jar包 1.Spring核心必须依赖的库:commons-logging-1.1.1.jar2.Spring IoC部分核心库: spring-beans-4.3.9.RELEASE.jar ...