在线客服
扫描二维码
下载博学谷APP扫描二维码
关注博学谷微信公众号
Java内存模型JMM基础知识及原理,学习过程中需要了解内存模型抽象结构、共享变量、JMM抽象结构模型、主内存与工作内存的相关知识,Java内存模型具有原子性、可见性、有序性三大特征。
什么是线程安全?当多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替运行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获取正确的结果,那这个对象是线程安全的。
出现线程安全的问题一般是因为主内存和工作内存数据不一致性和重排序导致的,而解决线程安全的问题最重要的就是理解这两种问题是怎么来的?理解它们的核心在于理解Java内存模型(JMM)。
在多线程条件下,多个线程肯定会相互协作完成一件事情,一般来说就会涉及到多个线程间相互通信告知彼此的状态以及当前的执行结果等,另外,为了性能优化,还会涉及到编译器指令重排序和处理器指令重排序。
一、内存模型抽象结构
线程间协作通信可以类比人与人之间的协作的方式,在现实生活中,之前网上有个流行语“你妈喊你回家吃饭了”,就以这个生活场景为例,小明在外面玩耍,小明妈妈在家里做饭,做完饭后准备叫小明回家吃饭,那么就存在两种方式:
小明妈妈要去上班了十分紧急这个时候手机又没有电了,于是就在桌子上贴了一张纸条“饭做好了,放在…”小明回家后看到纸条如愿吃到妈妈做的饭菜,那么,如果将小明妈妈和小明作为两个线程,那么这张纸条就是这两个线程间通信的共享变量,通过读写共享变量实现两个线程间协作;
还有一种方式就是,妈妈的手机还有电,妈妈在赶去坐公交的路上给小明打了个电话,这种方式就是通知机制来完成协作。同样,可以引申到线程间通信机制。
通过上面这个例子,应该有些认识。在并发编程中主要需要解决两个问题:1. 线程之间如何通信;2.线程之间如何完成同步。通信是指线程之间以何种机制来交换信息,主要有两种:共享内存和消息传递。可以分别类比上面的两个举例。Java内存模型是共享内存的并发模型,线程之间主要通过读-写共享变量来完成隐式通信。如果程序员不能理解Java的共享内存模型在编写并发程序时一定会遇到各种各样关于内存可见性的问题。
二、共享变量
在Java程序中所有实例域,静态域和数组元素都是放在堆内存中(所有线程均可访问到,是可以共享的),而局部变量,方法定义参数和异常处理器参数不会在线程间共享。共享数据会出现线程安全的问题,而非共享数据不会出现线程安全的问题。
三、JMM抽象结构模型
CPU的处理速度和主存的读写速度不是一个量级的(CPU的处理速度快很多),为了平衡这种巨大的差距,每个CPU都会有缓存。因此,共享变量会先放在主存中,每个线程都有属于自己的工作内存,并且会把位于主存中的共享变量拷贝到自己的工作内存,之后的读写操作均使用位于工作内存的变量副本,并在某个时刻将工作内存的变量副本写回到主存中去。JMM就从抽象层次定义了这种方式,并且JMM决定了一个线程对共享变量的写入何时对其他线程是可见的。
如图为JMM抽象示意图,线程A和线程B之间要完成通信的话,要经历如下两步:
线程A从主内存中将共享变量读入线程A的工作内存后并进行操作,之后将数据重新写回到主内存中;线程B从主存中读取最新的共享变量。
从横向去看看,线程A和线程B就好像通过共享变量在进行隐式通信。这其中有个意思的问题,如果线程A更新后数据并没有及时写回到主存,而此时线程B读到的是过期的数据,这就出现了“脏读”现象。可以通过同步机制来解决或者通过volatile关键字使得每次volatile变量都能够强制刷新到主存,从而对每个线程都是可见的。
四、主内存与工作内存
处理器上的寄存器的读写的速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存。加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
五、内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
lock(锁定):作用于主内存中的变量,它把一个变量标识为一个线程独占的状态;
unlock(解锁):作用于主内存中的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便后面的load动作使用;
load(载入):作用于工作内存中的变量,它把read操作从主内存中得到的变量值放入工作内存中的变量副本
use(使用):作用于工作内存中的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作;
assign(赋值):作用于工作内存中的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作;
store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送给主内存中以便随后的write操作使用;
write(操作):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。
— 申请免费试学名额 —
在职想转行提升,担心学不会?根据个人情况规划学习路线,闯关式自适应学习模式保证学习效果
讲师一对一辅导,在线答疑解惑,指导就业!
相关推荐 更多
折半插入排序讲解 干货教程
相信大家都了解折半插入排序的定义,即对插入排序算法的一种改进,所谓排序算法过程,就是不断的依次将元素插入前面已排好序的序列中。本文将从插入排序思想介绍、算法说明、折半插入排序的代码实现这些方面讲解折半插入排序讲解 ,感兴趣的小伙伴就接着看下去吧!
9433
2019-07-30 11:10:06
零基础Java在线学习方式有哪些?
零基础Java在线学习方式有哪些?总结起来,基本上就是四种方式,即多阅读相关书籍,观看学习视频,实战练习敲代码,与在线老师交流沟通。无论是在线自学也好,还是报线上的培训班,最有效的Java学习方式,也就是以上这些。下面小编来详细为大家讲解Java在线学习具体要怎么做。
5656
2019-09-29 10:31:58
MySQL数据库性能优化是什么?
MySQL数据库目前已被Oracle收购,并发展处多个版本。MySQL是一种开放源代码的关系型数据库管理系统RDBMS,使用最常用的数据库管理语言--结构化查询语言SQL进行数据库管理。
5138
2019-11-22 15:44:54
2019年12月Github上优秀的Java开源项目盘点
无论是作为已经有一定开发经验的Java程序员还是正在学习Java语言的同学,做开源项目都是大家学习和提升编程能力的最佳途径。在程序员不断攀登技术这座大山的时候,需要不断练习和磨练自己的技能,而优秀的开源项目就是帮助我们攀登的利器。本文为大家盘点了2019年12月份GitHub上优秀的Java开源项目,下面我们一起来看看吧!
7618
2020-01-14 19:42:17
Java常用设计模式及应用场景介绍
Java常用设计模式有哪些?设计模式是设计代码结构,方便开发或后期调整,学习Java必须要掌握一些常用设计模式,如单例模式、模板方法、工厂模式、建造者模式、适配器模式等。主要培养常用设计模式和代码抽取优化能力,可能涉及6大设计原则及23种设计模式。
5357
2021-04-12 16:02:05