并发之初章Java内存模型
》》》》》》博客地址《《《《《《
》》》》》》首发博客《《《《《《
前言
首先我们在了解java内存模型之前先看一下计算机内存模型,理解了计算机内存模型的话后面在看JMM就会简单的多,上篇文章我是直接写的。
计算机内存
计算机是由CPU、主存、磁盘等组成的(简单引出问题熬)我们都知道计算机执行程序的指令都是由CPU来执行的,执行的时候是要处理数据的,这些数据通常存储在主存中。
如图所示,这时候问题来了,CPU的执行速度越来越快,然后内存倒是没什么进展,这样的话CPU的读写操作就会非常耗时,效率不就很低了?
所以这个时候就出现了高速缓存(Cache)来解决这个问题,那么缓存是什么呢?缓存其实就是保存的数据备存,特点是快。所以这个时候程序的执行过程就变成了这个样子:首先在运行的时候会把数据从主存中赋值一份放在缓存中,然后CPU在运算的时候就直接去缓存中读写数据,等执行结束后在把数据刷新到主存中。这样一来就大大的提高了执行的速度。我们来看一下流程图:
可以看出,运行的时候L1缓存先把数据从主存中读取出来,然后CPU操作的数据是从缓存中读取,当数据执行完毕,在从缓存中刷新到主存中。随着CPU的执行能力越来越强,一层缓存已经满足不了需求了,这时候就出现了2级缓存(L2Cache)3级缓存(L3Cache),每级缓存都存储的是下一级缓存的一部分数据。
那么当CPU需要数据的时候就会这样执行:首先去一级缓存(L1Cache)查找,如果一级缓存没有就去二级缓存(L2Cache)查找,二级缓存没有就去三级缓存(L3Cache)查找,如果缓存中没有,就去主存中查找。 那么问题来了。
缓存一致性
现代计算机已经不是单个CPU,有多个CPU每个CPU还可能会有多核,单核CPU只有一套缓存分别就是上面所说的L1、L2、L3如图所示:
如果CPU有多个核心的话,就是每个核心都有L1缓存或者有L2缓存,而共享L3缓存或者L2缓存。
我们来看一下结构图:
这个时候每个核心都有自己的高速缓存,它们又共享同一主存,就会造成缓存一致性的问题,在多线程同时访问同一共享数据的情况下,每个线程都是操作自己缓存的数据副本,这个时候就会出现每个缓存中的共享数据存在不一致的情况。多个处理器运算任务都涉及同一块主存,需要一种协议可以保障数据的一致性,这类协议有MSI、MESI、MOSI及Dragon Protocol等。
处理器优化
上面了解到提高CPU的效率就是在CPU和主存直接增加高速缓存,增加高速缓存会造成缓存不一致的问题,除了缓存不一致的问题,还有一种问题就是为了能让处理器内部的运算单元能够尽量的被充分利用处理器可能会对输入代码进行乱序执行,并且处理器会在计算之后将乱序的代码进行结果重组来保证结果的一致性。在Java虚拟机中也有类似的指令重排序。
思考
这篇文章其实是讲述java内存模型的,为什么会和计算机硬件扯上关系呢?注意到上面有说到多线程的情况下会造成缓存不一致的问题,提到多线程就离不开并发,想到并发的话就离不开三大问题,可见性,原子性,有序性的问题。那这三种特性不就是上面所说到的缓存不一致,处理器优化和指令重排序问题吗。这这样看来缓存不一致不就是可见性的问题,而原子性不就是处理器优化所导致的原子性问题,指令重排序就是导致有序性的问题。那么Java内存模型又是什么呢?
java内存模型
Java内存模型的作用就是用来屏蔽掉不同操作系统中的内存差异性来保持并发的一致性。同时JMM也规范了JVM如何与计算机内存进行交互。简单的来说java内存模型就是Java自己的一套协议来屏蔽掉各种硬件和操作系统的内存访问差异,实现平台一致性达到最终的"一次编写,到处运行"。看到这里就知道了Jmm是用来做什么的。同时Java内存模型可以理解为java并发内存模型。然后JMM
通信
Java内存模型(以下简称JMM)规定了,所有变量都存储在主内存中,每个线程都有自己的本地缓存,所以线程中对变量的操作都必须在本地缓存中进行并不是直接操作主内存,线程之间的无法访问对方线程的变量,想要通信的话就只能通过主内存进行通信。
JMM抽象示意图:
从上图可以看出每个线程都有一个本地内存,如果线程想要通信的话要执行一下步骤:
- A线程先把本地内存的值写入主内存
- B线程从主内存中去读取出A线程写的值
具体通信规则可以参考我上一篇文章:Java内存模型里面定义了八种通信规则。
到这里就对JMM有个清晰的理解了。JMM其实是一种规范,其主要目的就是为了解决多线程通过共享内存进行通信时所产生的本地内存数据不一致,编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。
解决的问题
JMM所解决的问题离不开我们上面所说的三大特性:可见性、原子性、有序性.
原子性:在java中使用synchronized关键字保证代码的原子性,synchronized实现原理后面会单独写一篇文章。
可见性:volatile关键字保证了多线程操控变量的可见性,同时synchronized和final也可以保证变量的可见性,注意:volatile并不保证原子性,所以什么时候用volatile一定要注意。
有序性:volatile可以禁用指令重排,synchronized关键字保证同一时刻只允许一条线程操作所以我们可以发现synchronized可以解决三种问题,所以使用synchronized关键字比较多,但是synchronized只允许一个线程进行操作,会造成上下文切换的效率问题。
总结
通过上文一定对JMM是什么,和有什么作用有了一定的理解这里推荐《深入理解Java虚拟机》
并发之初章Java内存模型的更多相关文章
- 深入理解java虚拟机-第12章Java内存模型与线程
第12章 Java内存模型与线程 Java内存模型 主内存与工作内存: java内存模型规定了所有的变量都在主内存中,每条线程还有自己的工作内存. 工作内存中保存了该线程使用的主内存副本拷贝,线程对 ...
- (第三章)Java内存模型(下)
一.happens-before happens-before是JMM最核心的概念.对于Java程序员来说,理解happens-before是理解JMM的关键. 1.1 JMM的设计 从JMM设计者的 ...
- (第三章)Java内存模型(上)
一.java内存模型的基础 1.1 并发编程模型的两个关键问题 在并发编程中,需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来 ...
- 第三章 Java内存模型(上)
本章大致分为4部分: Java内存模型的基础:主要介绍内存模型相关的基本概念 Java内存模型中的顺序一致性:主要介绍重排序和顺序一致性内存模型 同步原语:主要介绍3个同步原语(synchroized ...
- 《深入理解Java虚拟机》-----第12章 Java内存模型与线程
概述 多任务处理在现代计算机操作系统中几乎已是一项必备的功能了.在许多情况下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统速 ...
- (第三章)Java内存模型(中)
一.volatile的内存语义 1.1 volatile的特性 理解volatile特性的一个好办法是把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步.下面通过具体 ...
- 《Java并发编程实战》第十六章 Java内存模型 读书笔记
Java内存模型是保障多线程安全的根基,这里不过认识型的理解总结并未深入研究. 一.什么是内存模型,为什么须要它 Java内存模型(Java Memory Model)并发相关的安全公布,同步策略的规 ...
- 第十二章 Java内存模型与线程
Java内存模型(Java Memory Model,JMM): 主内存与工作内存:Java内存模型主要是定义程序中各个变量的访问规则.Java内存模型规定了所有的变量都存储在主内存(Main Mem ...
- java并发编程实战:第十六章----Java内存模型
一.什么是内存模型,为什么要使用它 如果缺少同步,那么将会有许多因素使得线程无法立即甚至永远看到一个线程的操作结果 编译器把变量保存在本地寄存器而不是内存中 编译器中生成的指令顺序,可以与源代码中的顺 ...
随机推荐
- 使用sar进行性能分析
sar可用于监控Linux系统性能,帮助我们分析性能瓶颈.sar工具的使用方式为”sar [选项] intervar [count]”,其中interval为统计信息采样时间,count为采样次数. ...
- 微服务与网关技术(SIA-GateWay)
一.背景 软件架构,总是在不断的演进中... 把时间退回到二十年之前,当时企业级领域研发主要推崇的还是C/S模式,PB.Delphi这样的开发软件是企业应用开发的主流.随着时间的推移,基于浏览器的B/ ...
- 把Python项目打包成exe文件
我们很多时候,写好的程序需要打包成.exe文件才可以发给客户,那么今天我就来谈一谈,如何将一个写好的Python程序打包成exe文件! 首先,我们我们使用到的工具是python 3.7 和 Pyins ...
- Appium+python自动化(三十一)- 元芳,你怎么看? - 日志收集-logging(超详解)
简介 生活中的日志是记录你生活的点点滴滴,让它把你内心的世界表露出来,更好的诠释自己的内心世界,而电脑里的日志是有价值的信息宝库. 日志文件是专门用于记录系统操作事件的记录文件或文件集合,操作系统有操 ...
- C#_会员管理系统
https://www.cnblogs.com/start-from-scratch/p/5420588.html
- 11.源码分析---SOFARPC数据透传是实现的?
先把栗子放上,让大家方便测试用: Service端 public static void main(String[] args) { ServerConfig serverConfig = new S ...
- Oracle EM的重新配置和界面语言修改
实际在国内的DBA日常工作中,几乎很少会用到EM进行日常管理.但在Oracle的考试中,为了快速完成某些场景的应答,还是推荐使用EM进行操作的. 1.重新配置EM 2.修改界面语言 1.重新配置EM ...
- python学习——函数参数
一.为什么要使用函数 函数能提高应用的模块性,和代码的重复利用率. 二.函数的参数 位置参数:从左至右进行匹配 一般情况,也就是我们迄今为止最常用的方法,是通过位置进行匹配把参数值传递给函数头部的参数 ...
- CodeForces 909E
题意略. 思路:一个拓扑排序的题目吧.肯定是要先处理后面那个任务,再处理前面那个任务,我的思路是尽力先把主处理器能操作的先操作完,然后再把副处理器能操作完的再操作完,这样循环,直到处理完全部. 定义t ...
- Python之流程控制——if...else...
Python之流程控制--if...else... 一.流程控制 假如把程序比做走路,那我们到现在为止,一直走的都是直路,还没遇到过分岔口.当遇到分岔口时,你得判断哪条岔路是你要走的路,如果我们想让程 ...