资讯专栏INFORMATION COLUMN

深入理解volatile类型——从Java虚拟机内存模型角度

mushang / 2298人阅读

摘要:本文从内存模型角度,探讨的实现原理。通过共享内存或者消息通知这两种方法,可以实现通信或同步。基于共享内存的线程通信是隐式的,线程同步是显式的而基于消息通知的线程通信是显式的,线程同步是隐式的。锁规则锁的解锁,于于锁的获取或加锁。

一、前言

在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)到主内存,就是对于其它线程“不可见”的。

JMM就是通过控制主内存与每个线程的本地内存之间的交互,来为Java程序员提供可见性的保证的

三、volatile类型的内存语义

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操作或复合操作,整体上不具有有序性

适用于对volatile变量的写操作很少而读操作很多的环境

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70451.html

相关文章

  • 深入理解JVM》读书笔记

    摘要:抽时间重新读了一遍深入理解一书。验证确保文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。可见性可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。 抽时间重新读了一遍《深入理解JVM》一书。以下为摘录内容。 1 java内存区域 showImg(https://segmentfault.com/img/bVboDgk?w=617&h=365...

    idealcn 评论0 收藏0
  • Week 1 - Java 多线程 - Java 内存模型

    摘要:目的是解决由于多线程通过共享内存进行通信时,存在的原子性可见性缓存一致性以及有序性问题。最多只有一个线程能持有锁。线程加入规则对象的结束先行发生于方法返回。 前言 学习情况记录 时间:week 1 SMART子目标 :Java 多线程 学习Java多线程,要了解多线程可能出现的并发现象,了解Java内存模型的知识是必不可少的。 对学习到的重要知识点进行的记录。 注:这里提到的是Ja...

    zhaofeihao 评论0 收藏0
  • 读书笔记之深入理解Java虚拟

    摘要:前言本文内容基本摘抄自深入理解虚拟机,以供复习之用,没有多少参考价值。此区域是唯一一个在虚拟机规范中没有规定任何情况的区域。堆是所有线程共享的内存区域,在虚拟机启动时创建。虚拟机上把方法区称为永久代。 前言 本文内容基本摘抄自《深入理解Java虚拟机》,以供复习之用,没有多少参考价值。想要更详细了解请参考原书。 第二章 1.运行时数据区域 showImg(https://segment...

    jaysun 评论0 收藏0
  • Java问题汇总,持续更新到GitHub

    摘要:目录介绍问题汇总具体问题好消息博客笔记大汇总年月到至今,包括基础及深入知识点,技术博客,学习笔记等等,还包括平时开发中遇到的汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善开源的文件是格式的同时也开源了生活博客,从年 目录介绍 00.Java问题汇总 01.具体问题 好消息 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技...

    beita 评论0 收藏0
  • jvm原理

    摘要:在之前,它是一个备受争议的关键字,因为在程序中使用它往往收集器理解和原理分析简称,是后提供的面向大内存区数到数多核系统的收集器,能够实现软停顿目标收集并且具有高吞吐量具有更可预测的停顿时间。 35 个 Java 代码性能优化总结 优化代码可以减小代码的体积,提高代码运行的效率。 从 JVM 内存模型谈线程安全 小白哥带你打通任督二脉 Java使用读写锁替代同步锁 应用情景 前一阵有个做...

    lufficc 评论0 收藏0

发表评论

0条评论

mushang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<