Java并发编程:Java内存模型JMM
简介
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的更多相关文章
- Java并发编程、内存模型与Volatile
http://www.importnew.com/24082.html volatile关键字 http://www.importnew.com/16142.html ConcurrentHash ...
- Java并发编程-Java内存模型
JVM内存结构与Java内存模型经常会混淆在一起,本文将对Java内存模型进行详细说明,并解释Java内存模型在线程通信方面起到的作用. 我们常说的JVM内存模式指的是JVM的内存分区:而Java内存 ...
- 高并发第二弹:并发概念及内存模型(JMM)
高并发第二弹:并发概念及内存模型(JMM) 感谢 : 深入Java内存模型 http://www.importnew.com/10589.html, cpu缓存一致性 https://www.cnbl ...
- x86-TSO : 适用于x86体系架构并发编程的内存模型
Abstract : 如今大数据,云计算,分布式系统等对算力要求高的方向如火如荼.提升计算机算力的一个低成本方法是增加CPU核心,而不是提高单个硬件工作效率. 这就要求软件开发者们能准确,熟悉地运用高 ...
- 【并发编程】- 内存模型(针对JSR-133内存模型)篇
并发编程模型 1.两个关键问题 1)线程之间如何通信 共享内存 程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信 消息传递 程之间没有公共状态,线程之间必须通过发送消息来显式进行通信 ...
- Java并发编程:Java Thread 的 sleep() 和 wait() 的区别
1. start 和 run 方法解释: 1) start: 用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码.通过调用Thread类 ...
- Java并发编程:Java Thread 的 run() 与 start() 的区别
1. sleep 和 wait 方法解释 sleep()方法是Thread类里面的,主要的意义就是让当前线程停止执行,让出cpu给其他的线程,但是不会释放对象锁资源以及监控的状态,当指定的时间到了之后 ...
- Java并发编程:Java Thread方法join的简单总结
虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结. 一.作用 Thread类中的join方法的主要作用就是同步,它可以使得线程之间 ...
- 《Java并发编程的艺术》笔记
第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种:无锁并发编程.CAS算法.使用最少线程.使 ...
- java并发编程资料
并发这玩意很有用,把自己在网上看过觉得总结的很好的资料分享出来.猛击下面的地址查看吧 java并发编程:线程池的使用说明 java并发编程系列文章 Java并发性和多线程专题 并发工具类 Java 7 ...
随机推荐
- Java补强转
/* 对于byte/short/char三种类型来说,如果右侧赋值的数值没有超过范围, 那么javac编译器将会自动隐含地为我们补上一个(byte)(short)(char). 1. 如果没有超过左侧 ...
- Kakfa概述及安装过程
一.概述 1. Kafka是由LinkedIn(领英)开发的一个分布式的消息系统,最初是用作LinkedIn的活动流(Activity Stream)和运营数据处理的基础 a. 活动流数据包括页面访问 ...
- 批量导出存储在msdb库的SSIS包
http://blog.51cto.com/ultrasql/1924464 use msdb go IF OBJECT_ID('msdb.dbo.usp_ExportSSISPkgs') IS NO ...
- Python爬虫:urllib库的基本使用
请求网址获取网页代码 import urllib.request url = "http://www.baidu.com" response = urllib.request.ur ...
- 【代码学习】PYHTON 元组
Python的元组与列表类似,不同之处在于元组的元素不能修改.也可进行分片 和 连接操作. 元组使用小括号,列表使用方括号. 一.访问元组 #coding=utf-8 Tuple = ('name', ...
- Euler Sums系列(三)
\[\Large\sum_{n=1}^{\infty}\frac{\left(H_{n}^{(2)}\right)^{2}}{n^{2}}=\frac{19}{24}\zeta(6)+\zeta^{2 ...
- 并行效果&迭代器
具体文章:ALEX的文章 https://www.cnblogs.com/alex3714/articles/5765046.html 串行的并行效果: import time def consume ...
- request库解析中文
官网地址: http://cn.python-requests.org/zh_CN/latest/ 高级用法 本篇文档涵盖了 Requests 的一些高级特性. 会话对象 会话对象让你能够跨请求保持某 ...
- springboot集成拦截器
一.首先对HandlerInterceptor进行封装,封装为MappingInterceptor.封装的方法里添加拦截器起作用的路径addPathPatterns(),及需要排除路径的方法exclu ...
- leetCode练题——13. Roman to Integer
1.题目13. Roman to Integer Roman numerals are represented by seven different symbols: I, V, X, L, C, D ...