栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

被JAVA内存模型绕晕了?看来看这一篇

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

被JAVA内存模型绕晕了?看来看这一篇

文章目录
  • 前言
  • 一、为什么要有内存模型
    • 1.1 CPU和缓存一致性
    • 1.2线程切换和指令重排
    • 1.3并发编程的核心问题
  • 二、JAVA内存模型(JMM)
  • 三、JAVA内存模型的实现
  • 总结


前言

网上有很多关于JAVA内存模型的文章,但大多只讲解了JAVA内存模型本身的概念,很少提到JAVA内存模型出现的原因是什么,导致看完之后自己的思维更加混乱。本文简单介绍为什么要有内存模型以及JAVA内存模型的基本概念供参考学习。


一、为什么要有内存模型 1.1 CPU和缓存一致性

我们应该都知道,计算机在执行程序的时候,每条指令都是在CPU中执行的,而执行的时候,又免不了要和数据打交道。而计算机上面的数据,是存放在主存当中的,也就是计算机的物理内存。

刚开始,还相安无事的,但是随着CPU技术的发展,CPU的执行速度越来越快。而由于内存的技术并没有太大的变化,所以从内存中读取和写入数据的过程和CPU的执行速度比起来差距就会越来越大,这就导致CPU每次操作内存都要耗费很多等待时间。

例如:你是cpu,小伙伴是内存,刚开始你和你的小伙伴其乐融融,后来你读到了博士,你的每一个命令,由于小伙伴的理解能力和执行能力欠缺,就会耗费很多时间,这就无形拖慢了效率。

可是,不能因为内存的读写速度慢,就不发展CPU技术了吧,总不能让内存成为计算机处理的瓶颈吧。

解决办法:
在CPU和内存之间增加高速缓存。缓存的概念大家都知道,就是保存一份数据拷贝。他的特点是速度快,内存小,并且昂贵。

那么,程序的执行过程就变成了:
当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。

但是这会出现什么问题?
在CPU和主存之间增加缓存,在多线程场景下就可能存在缓存一致性问题,也就是说,在多核CPU中,每个核的自己的缓存中,关于同一个数据的缓存内容可能不一致。

1.2线程切换和指令重排

Java 并发程序都是基于多线程的,自然也会涉及到任务切换,任务切换的时机大多数是在时间片结束的时候。这种切换可能会导致问题。
两个线程 A 和 B 同时执行 count++, 即便 count 使用 volatile 修辞,我们预期的结果值是 2,但实际可能是 1。

编译器为了优化性能,有时候会改变程序中语句的先后顺序,比如Java虚拟机的即时编译器(JIT)也会做指令重排。
如果任由处理器优化和编译器对指令重排的话,就可能导致各种各样的问题。

1.3并发编程的核心问题

原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。
可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
有序性即程序执行的顺序按照代码的先后顺序执行。

缓存一致性问题其实就是可见性问题。而线程切换是可以导致原子性问题的。指令重排即会导致有序性问题。


二、JAVA内存模型(JMM)

前面提到的,缓存一致性问题、指令重排问题是硬件的不断升级导致的。那么,有没有什么机制可以很好的解决上面的这些问题呢?
为了保证并发编程中可以满足原子性、可见性及有序性。有一个重要的概念,那就是——内存模型。

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

JMM就作用于工作内存和主存之间数据同步过程。他规定了如何做数据同步以及什么时候做数据同步。


三、JAVA内存模型的实现

Java内存模型封装了底层的实现后提供给程序员使用的一些关键字:比如volatile、synchronized、final、concurrent包等。
原子性:在Java中,为了保证原子性,提供了两个高级的字节码指令monitorenter和monitorexit。在synchronized的实现原理文章中,介绍过,这两个字节码,在Java中对应的关键字就是synchronized。

可见性:Java中的volatile关键字提供了一个功能,那就是被其修饰的变量修改后将新值同步回主内存,变量读取前从主内存刷新变量值。因此,可以使用volatile来保证多线程操作时变量的可见性。

有序性:在Java中,可以使用synchronized和volatile来保证多线程之间操作的有序性。volatile关键字会禁止指令重排,synchronized关键字保证同一时刻只允许一条线程操作。


总结

JMM是一种规范,目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序等带来的问题。除了定义了一套规范,还提供了一系列原语,封装了底层实现后,供开发者直接使用。


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995290.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号