文档章节

Java并发学习之Volatile及内存模型探究

小灰灰Blog
 小灰灰Blog
发布于 2017/11/02 23:25
字数 1350
阅读 24
收藏 1

volatile工作原理

java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排他锁单独获得这个变量。

Java语言提供了volatile,在某些情况下比锁更加方便。如果一个字段被声明成volatile,java线程内存模型确保所有线程看到这个变量的值是一致的。

若想清楚理解volatile关键字是如何保障共享变量在多线程之间正常使用的需要了解以下几点

  • java的内存模型
  • 原子性,可见性,有序性
  • volatile的工作原理
  • 测试case

I. Java的内存模型

1. 内存模型

精简一点,概念如下:

指令在CPU中执行,CPU运行速度较快,因此为减少从内存中频繁读写数据的开销,在cpu与内存的操作之间,有个高速缓存的的区域

获取数据流程:

  • 从缓存中获取Data
  • 缓存中存在,则直接返回
  • 缓存中不存在
    • 从内存中获取Data数据
    • 将Data数据写入缓存
    • 返回Data数据

上面的流程中,第一步会导致一致性问题,分析如下

若内存中Data已更新,但缓存中数据未更新,此时返回缓存中Data,返回的是旧数据

解决方案:

  • 总线上加LOCK#锁
    • 因为CPU和其他部件进行通信都是通过总线来进行的,如果对总线加LOCK#锁的话,也就是说阻塞了其他CPU对其他部件访问(如内存),从而使得只能有一个CPU能使用这个变量的内存
  • 缓存一致性协议
    • 在内存中数据发生变更后,同时使所有缓存中的数据失效,在访问缓存中数据时,优先判断是否已经失效,若失效则从内存中获取最新的数据回写到缓存中,并返回

volatile

2. Java内存模型

java内存模型,主要是为了屏蔽不同的硬件,操作系统的内存访问差异,使Java程序可以达到跨平台的目的,从而定义的一套模型

线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存保存该线程读写共享变量的副本

因此也存在上面的一致性问题,即如何保证线程对共享变量的修改后,其他的线程能访问到最新的共享变量

指令重排序

Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性

举例说明

int i;
boolean ans;

i = 10;
ans = true;

上面的代码中,ians的赋值先后顺序由于指令重排,可能会出现ans=true时,i依然为0的情况

II. 原子性,可见性,顺序性

原子性

表示不可再继续分割

  • java中除了 (long,double)的赋值是非原子性的,其他的基本变量、对象的赋值都是原子性的
  • ++/-- 操作是非原子性的

可见性

一个线程对共享变量的修改,确保对其他线程可见(即另一个线程能访问到修改后的数据)

  • volatile进行声明变量,保证可见

顺序行

程序执行的顺序按照代码的先后顺序执行

  • volatile 禁止指令重排
  • 在修改变量时,加锁(synchronized,lock),确保同一时刻只有一个线程修改变量

III. Volatile关键字

用法

  • 在变量前面加上volatile即可

作用

  • 确保共享变量的修改,对其他线程都是立即可见的
  • 禁止指令重排(即当访问or修改volatile修饰的共享变量时,确保前面的代码都执行完了)

原理和实现机制

  • 修改volatile声明的共享变量,会强制要求修改后的值写入内存,并失效其他线程的本地内存中的副本
  • 汇编之后,加入volatile关键字时,会多出一个lock前缀指令
  • 它确保指令重排序时不会把其后面的指令排到lock指令之前,也不会把前面的指令排到lock指令之后

IV. 使用场景&小结

1.volatile关键字无法保证操作的原子性

2.volatile关键字,禁止共享变量的指令重排,确保修改对所有线程立即可见

3.使用场景

  • 对变量的写操作不依赖于当前值
    • (因为volatile不保证原子性,若依赖自己的值)
  • 变量独立使用
    • 如 volatile 定义变量i,还有一个没有被volatile修饰的变量j
    • int ans = i + j;(也无法保障准确性)

经典的单例case写法

class Singleton{
    private volatile static Singleton instance = null;
     
    private Singleton() {
    }
     
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized (Singleton.class) {
                if(instance==null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

参考

扫描关注,java分享

https://static.oschina.net/uploads/img/201710/13203703_6IVg.jpg

© 著作权归作者所有

共有 人打赏支持
小灰灰Blog
粉丝 187
博文 190
码字总数 334310
作品 0
武汉
程序员
私信 提问
【并发编程】一文带你读懂深入理解Java内存模型(面试版本)

     并发编程这一块内容,是高级资深工程师必备知识点,25K起如果不懂并发编程,那基本到顶。但是并发编程内容庞杂,如何系统学习?本专题将会系统讲解并发编程的所有知识点,包括但不限...

java进阶架构师
2018/12/26
0
0
来,了解一下Java内存模型(JMM)

网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文...

android 开发
2018/08/21
0
0
再有人问你Java内存模型是什么,就把这篇文章发给他。

前几天,发了一篇文章,介绍了一下JVM内存结构、Java内存模型以及Java对象模型之间的区别。有很多小伙伴反馈希望可以深入的讲解下每个知识点。Java内存模型,是这三个知识点当中最晦涩难懂的...

Java架构
2018/07/11
0
0
再有人问你Java内存模型是什么,就把这篇文章发给他

网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文...

java高级架构牛人
2018/07/04
0
0
再有人问你volatile是什么,就把这篇文章发给他

Java语言为了解决并发编程中存在的原子性、可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized、volatile、final、concurren包等。在前一篇文章中,我们也介绍了syn...

Java小铺
2018/08/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

乱入Linux界的我是如何学习的

欢迎来到建哥学Linux,咳!咳!咳!开个玩笑哈,我是一个IT男,IT界的入门选手,正在学习Linux。 在之前,一直想进军IT界,学习IT技术,但是苦于没有人指导,也不知道学什么,最开始我自己在...

linuxprobe16
39分钟前
4
0
OSChina 周日乱弹 —— 没时间 没头发 但有钱

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @开源中国总经办主任 :分享齐一的单曲《这个年纪》 《这个年纪》- 齐一 手机党少年们想听歌,请使劲儿戳(这里) @肿肿卷 :我真的可以睡一天...

小小编辑
今天
51
4
Django进阶 1.1 ORM基础—ORM 1.2.1 增删改查之查询 1.2.2 删改增 (1) 1.2.3 删改增 (2)

ORM基础 ORM是Django操作数据库的API,Django的作者将sql语句封装在里面供我们使用。 我们前面还提到过Django提供一个模拟数据库的工具,sqlite,供我们学习测试使用。 如果我们想使用mysql...

隐匿的蚂蚁
今天
3
0
Windows 上安装 Scala

在安装 Scala 之前需要先安装 Java 环境,具体安装的详细方法就不在这里描述了。 您可以自行搜索我们网站中的内容获得其他网站的帮助来获得如何安装 Java 环境的方法。 接下来,我们可以从 ...

honeymose
今天
3
0
数据库篇多表操作

第1章 多表操作 实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系...

stars永恒
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部