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

前言

首先我们在了解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内存模型的更多相关文章

  1. 深入理解java虚拟机-第12章Java内存模型与线程

    第12章 Java内存模型与线程 Java内存模型  主内存与工作内存: java内存模型规定了所有的变量都在主内存中,每条线程还有自己的工作内存. 工作内存中保存了该线程使用的主内存副本拷贝,线程对 ...

  2. (第三章)Java内存模型(下)

    一.happens-before happens-before是JMM最核心的概念.对于Java程序员来说,理解happens-before是理解JMM的关键. 1.1 JMM的设计 从JMM设计者的 ...

  3. (第三章)Java内存模型(上)

    一.java内存模型的基础 1.1 并发编程模型的两个关键问题 在并发编程中,需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来 ...

  4. 第三章 Java内存模型(上)

    本章大致分为4部分: Java内存模型的基础:主要介绍内存模型相关的基本概念 Java内存模型中的顺序一致性:主要介绍重排序和顺序一致性内存模型 同步原语:主要介绍3个同步原语(synchroized ...

  5. 《深入理解Java虚拟机》-----第12章 Java内存模型与线程

    概述 多任务处理在现代计算机操作系统中几乎已是一项必备的功能了.在许多情况下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统速 ...

  6. (第三章)Java内存模型(中)

    一.volatile的内存语义 1.1 volatile的特性 理解volatile特性的一个好办法是把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步.下面通过具体 ...

  7. 《Java并发编程实战》第十六章 Java内存模型 读书笔记

    Java内存模型是保障多线程安全的根基,这里不过认识型的理解总结并未深入研究. 一.什么是内存模型,为什么须要它 Java内存模型(Java Memory Model)并发相关的安全公布,同步策略的规 ...

  8. 第十二章 Java内存模型与线程

    Java内存模型(Java Memory Model,JMM): 主内存与工作内存:Java内存模型主要是定义程序中各个变量的访问规则.Java内存模型规定了所有的变量都存储在主内存(Main Mem ...

  9. java并发编程实战:第十六章----Java内存模型

    一.什么是内存模型,为什么要使用它 如果缺少同步,那么将会有许多因素使得线程无法立即甚至永远看到一个线程的操作结果 编译器把变量保存在本地寄存器而不是内存中 编译器中生成的指令顺序,可以与源代码中的顺 ...

随机推荐

  1. java并发编程(七)----(JUC)ReadWriteLock

    前面我们已经分析过JUC包里面的Lock锁,ReentrantLock锁和semaphore信号量机制.Lock锁实现了比synchronized更灵活的锁机制,Reentrantlock是Lock的 ...

  2. js学习之数据类型

    js学习之数据类型 基础类型:number string boolean null undefined 引用类型:object array function undefined值是派生自null值的( ...

  3. 「求助」关于MacOS 适配不了SOIL的问题 以及我自己愚蠢的解决办法

    我的环境 macOS High Sierra 10.13.6 (2018) 我的SOIL源是通过 终端 git clone https://github.com/DeVaukz/SOIL 直接从gay ...

  4. 啥?修改下 URL 就能高速下载网盘资源和百度文库?

    下载百度资源和百度文库资料是大家常有的需求,不过多数方法都需要下载些软件什么的才能实现. 今天给大家介绍一个简单方法,修改下 URL 就能直接在浏览器中高速下载网盘资源和百度文库资料. [下载百度网盘 ...

  5. 纯数据结构Java实现(6/11)(二叉堆&优先队列)

    堆其实也是树结构(或者说基于树结构),一般可以用堆实现优先队列. 二叉堆 堆可以用于实现其他高层数据结构,比如优先队列 而要实现一个堆,可以借助二叉树,其实现称为: 二叉堆 (使用二叉树表示的堆). ...

  6. 服务链路跟踪 && 服务监控

    服务链路跟踪 背景 微服务以微出名,在实际的开发过程中,涉及到成百上千个服务,网络请求引起服务之间的调用极其复杂. 当请求不可用或者变慢时,需要及时排查出故障服务点成为了微服务维护的一大难关. 服务链 ...

  7. odoo模板中的t-标签用法

    在OpenERP中,通过QWeb来对模板进行渲染后加载到浏览器中,而模板中有许多的标签来定制各种需求变化,在这里记录学习过程中碰到的标签定义,以方便查询. 模板中的标签统一都是以"t-&qu ...

  8. Java线程之线程简介

    Java线程之线程简介 一.何谓线程 明为跟踪处理流程,实为跟踪线程 阅读程序时,我们会按处理流程来阅读. 首先执行这条语句 ↓ 然后执行这条语句 ↓ 接着再执行这条语句…… 我们就是按照上面这样的流 ...

  9. 你知道JavaScript这六种错误类型吗?

    前言 今日话题,了解JavaScript的错误处理机制. 一.ReferenceError 引用一个不存在的变量时发生的错误.将一个值分配给无法分配的对象,比如对函数的运行结果或者函数赋值. 举栗子 ...

  10. 2019nc#3

    题号 标题 已通过代码 题解/讨论 通过率 团队的状态 A Graph Games 点击查看 进入讨论 18/292 未通过 B Crazy Binary String 点击查看 1107/3615 ...