首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高并发编程-volatile详解

高并发编程-volatile详解

作者头像
JavaQ
发布2018-12-07 09:45:14
6310
发布2018-12-07 09:45:14
举报
文章被收录于专栏:JavaQJavaQ

主内存与工作内存

在介绍volatile之前,先简单了解一下Java内存模型。在Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽各个硬件平台和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果,笔者认为是定义了程序中变量的访问规则。

主内存

所有线程共享的区域,存储线程共享的数据,包括实例变量、静态变量和构成数组的对象的元素,不包括局部变量和方法参数。

工作内存

每个线程独享的区域,存储主内存中的数据拷贝。

Java内存模型规定所有的变量都是存在主内存中,每个线程都有自己的工作内存。每个线程对共享数据的读、写操作都只在各自的工作内存中,不能直接在主内存中进行;在各自工作内存中对数据操作完成后,同步到主内存中;线程间不能访问各自工作内存中的数据,只能通过主内存来完成。下面用一张图来展示线程、主内存和工作内存三者之间的交互关系。

volatile

当使用volatile关键字修饰共享变量(实例变量、静态变量)时,它将具备两个特性:可见性和禁止指令重排序优化。

可见性

变量被修改后的新值会立即写回主内存中,同时会使其它线程工作内存中的旧值失效,新值对其它线程来说是可见的,其它线程可以立即得到修改后的新值,因为volatile变量每次使用之前都需要从主内存刷新获取最新值。

关于volatile实现的可见性可能会误解,认为既然volatile变量所有的写操作都会立刻反应到其它线程中,那么对volatile变量进行并发操作就是安全的。有这个误解是因为忽略了原子性,volatile是不保证原子性的。对一个变量进行修改赋值操作,可能写的就是一条简单的i=i+1,但是底层实现上会需要多条字节码指令来完成,同时一条字节码指令也可能转化成多条机器码指令,在并发情况下,这些指令的执行不能保证原子性。

禁止指令重排序优化

指令重排序是指CPU在正确处理指令依赖(数据依赖)并且保障程序执行得到正确结果的情况下,调整代码的执行顺序,允许将多条指令不按照程序规定顺序分开发送给各相应电路单元处理。需要注意的是指令重排序不会影响到代码在单线程环境下的执行,会影响到多线程并发情况下执行的正确性。

volatile禁止指令重排序是通过lock前缀指令实现的,lock前缀的指令相当于一个内存屏障,指令重排序时不能把后面的指令重排序到lock前缀指令之前,同时它会强制将对工作内存的修改操作立即写入主内存中。

使用条件

虽然volatile可以实现最轻量级的同步机制,但是使用volatile修饰的变量必须满足以下两个条件:

  • 对变量的写操作不依赖于当前值,或者确保只有一个线程修改变量的值;
  • 该变量没有包含在具有其他变量的不变式中。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JavaQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 主内存与工作内存
    • 主内存
      • 工作内存
      • volatile
        • 可见性
          • 禁止指令重排序优化
          • 使用条件
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档