摘要:本文从内存模型角度,探讨的实现原理。通过共享内存或者消息通知这两种方法,可以实现通信或同步。基于共享内存的线程通信是隐式的,线程同步是显式的而基于消息通知的线程通信是显式的,线程同步是隐式的。锁规则锁的解锁,于于锁的获取或加锁。
一、前言
在java多线程编程中,volatile可以用来定义轻量级的共享变量,它比synchronized的使用成本更低,因为它不会引起线程上下文的切换和调度。所谓知己知彼、百战不殆。本文从JVM内存模型角度,探讨volatile的实现原理。在明白了volatile的实现原理后,再回过头来使用它,会有一种一览众山小的感觉吧,使用起来会更加得心应手。
二、Java内存模型(JMM) 1、并发编程关键问题多线程编程涉及到两个关键问题,线程之间的通信与同步。通信是指线程之间传递信息,同步是指控制线程操作的执行顺序。通过共享内存或者消息通知这两种方法,可以实现通信或同步。基于共享内存的线程通信是隐式的,线程同步是显式的;而基于消息通知的线程通信是显式的,线程同步是隐式的。JAVA是前者,即基于共享内存的隐式线程通信、显式线程同步。
2、happens-before模型JMM呈现给程序员的模型是happens-before模型,即:
顺序规则:(单)线程中的写操作的结果,happens before于于任意后续操作。
锁规则: 锁的解锁,happens before于于锁的获取或加锁。
volatile变量规则:volatile写操作,happens before于后续该变量的读操作是可见的。
传递性:A操作happens before于B操作,B操作happens before于C操作,则A操作happens before于C操作
这儿的happens-before,并不是指操作先于后续操作执行,而是指操作结果对于后续结果是可见的。
3、可见性在JMM中,每个线程的内存由两层构成:线程的“本地内存”、“主内存”。“本地内存”是JMM的一个抽象,本身是不存在的,它包括缓存、寄存器、写缓冲区、编译器及CPU的优化等。共享变量存放在“主内存”中,“本地内存”中存放的是共享变量的副本。当线程中发生对共享变量的写操作时,并不是直接写到“主内存”中的,而是先写到“本地内存”的写缓冲区中,只有当刷新(flush)到主内存后,才可能被其它线程加载到其“本地内存”中,此时我们说该共享变量是对其它线程“可见”的,反之如果没有刷新(flush)到主内存,就是对于其它线程“不可见”的。
三、volatile类型的内存语义JMM就是通过控制主内存与每个线程的本地内存之间的交互,来为Java程序员提供可见性的保证的
happens-before规则提供了对volatile变量可见性的保证,即volatile变量的写操作,对后续任意对该变量的读操作是可见的。
四、volatile类型的JMM实现再深入一些,JMM是如何实现happens-before模型中的volatile规则的呢?是通过限制这两种操作的重排序实现的。
重排序规则 | 第二个操作 | ||
---|---|---|---|
第一个操作 | volatile读 | volatile写 | 普通读/写 |
volatile读 | 禁止重排序(1) | 禁止重排序(2) | 禁止重排序(3) |
volatile写 | 禁止重排序(4) | 禁止重排序(5) | - |
普通读/写 | - | 禁止重排序(6) | - |
(1) 第一个操作是volatile读时,不可以重排序,否则读出来的结果,可能是被修改过了的。
(2)(5)(6),第二个是volatile写时,所有操作都不可以被重排序于其后面,因为要确保其写的结果对于后续操作可见。
多个volatile操作或复合操作,整体上不具有有序性
适用于对volatile变量的写操作很少而读操作很多的环境
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/70451.html
摘要:抽时间重新读了一遍深入理解一书。验证确保文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。可见性可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。 抽时间重新读了一遍《深入理解JVM》一书。以下为摘录内容。 1 java内存区域 showImg(https://segmentfault.com/img/bVboDgk?w=617&h=365...
摘要:目的是解决由于多线程通过共享内存进行通信时,存在的原子性可见性缓存一致性以及有序性问题。最多只有一个线程能持有锁。线程加入规则对象的结束先行发生于方法返回。 前言 学习情况记录 时间:week 1 SMART子目标 :Java 多线程 学习Java多线程,要了解多线程可能出现的并发现象,了解Java内存模型的知识是必不可少的。 对学习到的重要知识点进行的记录。 注:这里提到的是Ja...
摘要:前言本文内容基本摘抄自深入理解虚拟机,以供复习之用,没有多少参考价值。此区域是唯一一个在虚拟机规范中没有规定任何情况的区域。堆是所有线程共享的内存区域,在虚拟机启动时创建。虚拟机上把方法区称为永久代。 前言 本文内容基本摘抄自《深入理解Java虚拟机》,以供复习之用,没有多少参考价值。想要更详细了解请参考原书。 第二章 1.运行时数据区域 showImg(https://segment...
摘要:目录介绍问题汇总具体问题好消息博客笔记大汇总年月到至今,包括基础及深入知识点,技术博客,学习笔记等等,还包括平时开发中遇到的汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善开源的文件是格式的同时也开源了生活博客,从年 目录介绍 00.Java问题汇总 01.具体问题 好消息 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技...
阅读 2584·2021-09-28 09:35
阅读 3242·2021-09-03 10:28
阅读 2835·2019-08-30 15:43
阅读 1449·2019-08-30 14:04
阅读 1768·2019-08-29 17:02
阅读 1792·2019-08-26 13:59
阅读 664·2019-08-26 11:51
阅读 3224·2019-08-23 17:16