java volatile有什么用_Java程序大佬谈谈Java中Volatile关键字的作用!

volatile是用来标记一个JAVA变量存储在主内存(main memory)中,确切的说:每次写操作volatile变量时,将直接从电脑的主内存(main memory)中读取操作而不是从CPU Cache。

概述

可见性: 是指线程之间数据可见共享,一个线程修改的状态对另一个线程是可见的。比如:用volatile修饰的变量,就会确保变量在修改时,其它线程是可见的。。

在多线程中,对非volatile变量进行操作的时候,出于对性能的考虑,当对这些变量进行数据操作时,线程可能会从主内存里拷贝变量到CPU Cache中去。多核CPU环境中,多个线程分别在不同的CPU中运行,就意味着,多个线程都有可能将变量拷贝到当前运行的CPU Cache里。

如下图所示(多线程数据模型):a67d268ebd8ab3df948dc209643d7f6b.png

示例 - 非Volatile905ae06996a2e5f32e792a40c28cf598.png

c55abff9841f5562c8cf7f334d451ccb.png

结果表明,UPDATE线程虽修改数据,但是READER线程并未监听到数据的变动,当前线程操作的是当前CPU Cache里的数据,而不是从main memory获取的。

couner 的变量未使用volatile关键字修饰,即JVM无法保证有效的将CPU Cache的内容写入主存中。意味着 counter 变量在CPU Cache中的值可能会与主存中的值不一样。

如下图所示(无Volatile):2c75714daa7ed6fa36814818b378d3e5.png

示例 - Volatilec1e3ac09a5db482e9eed474ab2b9746f.png

结果表明,volatile修饰后的变量并不会达到Lock的效果,它只会保证线程可见性,但不保证原子性,在读取volatile变量和写入它的新值时,由于操作耗时较短,就会产生竞争条件:多个线程可能会读取到volatile变量的相同值,然后产生新值并写入主内存,这样将会覆盖互相的值。(有兴趣的可以在创建一个UPDATE线程测试效果)

如下图所示(Volatile):d11abf5bdbac340b627aa95c6fa9aa2a.png

Happens-Before 原则

从Java5之后volatile关键字不仅能用于保证变量从主存中进行读写操作,同时还遵循Happens-Before原则。如果T1线程写入了一个volatile变量然后T2线程读取该变量,那么T1线程写之前对其可见的所有变量,T2线程读取该volatile之后也会对其可见。

禁止JVM指令重排优化,一旦被volatile修饰的变量,赋值后多执行了一个load addl $0x0, (%esp)操作,相当于多了一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),单核CPU访问内存时,并不需要内存屏障;

看看下面这个示例:a876f08d8399b93163c62eb80d65669b.png

被volatile修饰过的变量 init在写操作之前,创建了非volatile变量的obj,因而T1线程在写入init后,会将obj也写入主内存中去。

由于T2线程启动的时候读取被volatile修饰过的init,因而变量 init 和变量 obj 都会被写入T2线程所使用的CPU缓存中去。当T2线程读取 obj 变量时,它将能看见被T1线程写入的东西。

总结适用场景线程可见,状态量标记87c0030204821457091fe92cd4531aed.png

屏障前后一致性,禁止指令重排db43f6a144a9b81eba31d245c9998de0.png

Java程序员学习交流群515675832,既有技术大佬,又有老司机开车,各位对Java感兴趣的可以来交流学习一下,快乐与技术一起进步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值