并发之初章Java内存模型

》》》》》》博客地址《《《《《《
》》》》》》首发博客《《《《《《java

前言

首先咱们在了解java内存模型以前先看一下计算机内存模型,理解了计算机内存模型的话后面在看JMM就会简单的多,上篇文章我是直接写的。缓存

计算机内存

计算机是由CPU、主存、磁盘等组成的(简单引出问题熬)咱们都知道计算机执行程序的指令都是由CPU来执行的,执行的时候是要处理数据的,这些数据一般存储在主存中。多线程

如图所示,这时候问题来了,CPU的执行速度愈来愈快,而后内存却是没什么进展,这样的话CPU的读写操做就会很是耗时,效率不就很低了?并发

因此这个时候就出现了高速缓存(Cache)来解决这个问题,那么缓存是什么呢?缓存其实就是保存的数据备存,特色是快。因此这个时候程序的执行过程就变成了这个样子:首先在运行的时候会把数据从主存中赋值一份放在缓存中,而后CPU在运算的时候就直接去缓存中读写数据,等执行结束后在把数据刷新到主存中。这样一来就大大的提升了执行的速度。咱们来看一下流程图:优化

能够看出,运行的时候L1缓存先把数据从主存中读取出来,而后CPU操做的数据是从缓存中读取,当数据执行完毕,在从缓存中刷新到主存中。随着CPU的执行能力愈来愈强,一层缓存已经知足不了需求了,这时候就出现了2级缓存(L2Cache)3级缓存(L3Cache),每级缓存都存储的是下一级缓存的一部分数据。操作系统

那么当CPU须要数据的时候就会这样执行:首先去一级缓存(L1Cache)查找,若是一级缓存没有就去二级缓存(L2Cache)查找,二级缓存没有就去三级缓存(L3Cache)查找,若是缓存中没有,就去主存中查找。 那么问题来了。线程

缓存一致性

现代计算机已经不是单个CPU,有多个CPU每一个CPU还可能会有多核,单核CPU只有一套缓存分别就是上面所说的L一、L二、L3如图所示:blog

若是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虚拟机》

相关文章
相关标签/搜索