3.JUC之volatile
原文链接:http://blog.csdn.net/zteny/article/details/54888629
一、简介
volatile是Java语言的关键字,用来修饰可变变量(即该变量不能被final
修饰),且必须是至少类内可见。所以它是可以修饰带static
的变量。这我自己下定义。
它是被设计用来修饰被不同线程访问和修改的变量。来自 百度百科
二、功能
volatile提供了一个高效的同步机制,她在某些情况下可以代替synchronized实现更轻量和高效的同步机制,同时也更为脆弱,更难于掌控。被volatile修饰的变量具有内存可见性,但不具有原子性。至于什么是可见性,前面已经做过简单介绍,接下来我们进一步来看什么是可见性。
1. 内存可见性
首先为什么会出现内存可见性问题呢?
想完全理解这个问题,请自行阅读《深入理解计算机系统》吧!这里简单说一下,
每个线程都有它自己的线程上下文,包括栈、栈指针、程序计数器、通用目的寄存器和条件码。所有的运行在一个进程里的共享该进程的整个虚拟地址空间。——来自《深入理解计算机系统》
下面这个说法可能并不严谨,甚至是有误,但对我们理解这个问题有帮忙。
如你所知,所有计算都发生CPU,然而它直接操作主存的效果比较远,不如CPU的缓存区,更远不如寄存器。其次,如上面所有的系统会为每个线程分配自己的线程上下文。在这两个大提前下,可能简化的理解为线程有自己的高速cache,即所有线程操作变量时,都不会直接操作主存。当发生cache miss时,从主存拷贝到cache,这些都是你懂的啦。跟所有的cache一样,都存在一致性的问题。
即是正常情况下什么时候发生cache冲刷回主存并不可控。
不正常情况下,退出临界区时即刻强制更新主存。另一种情况,即我们要讨论的volatile。被volatile修饰的变量比较特殊,表示直接操作主存,不需要通过cache。直接要用时直接从主存取(注意取出来还是会把值放在自己的上下文,这点后面需要用到),用完写直接回主存。这就是内存可见性。
2. 可不完全替代synchronized
之前整理synchronized的时候忘了讲synchronized怎么实现同步的,在这里顺便带出来吧。
synchronized是通过临界区实现同步的,临界区的同步方式是同一个时间只有最多一个线程进入临界区,也就是说只能保证原临界区具有原子性。这是什么意思呢,先来看一下面例子吧。
void barfoo() {
new Thread(() -> {
for(int v=0; v<100; v++) bar();
}).start();
new Thread(() -> {
for(int v=0; v<100; v++) foo();
}).start();
}
}
int v = 0;
void bar() {
final int t = v + 1;
v++;
try {
TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(10));
} catch (InterruptedException e) { }
if(t != v)System.out.println("not match");
}
synchronized void foo() {
final int t = v + 1;
v++;
try {
TimeUnit.MILLISECONDS.sleep(RandomUtils.nextInt(10));
} catch (InterruptedException e) { }
if(t != v)System.out.println("not match");
}
执行barfoo()
的结果打印了not match
。
synchronized只是通过线程在离开临界区时会把线程上下文冲刷回主存,从而实现一致性,但对于变量v
而言不具备原子性,更无法保证能够一致性。
volatile可部分替代synchronized,也就是说在特定条件或者场景下可以替代synchronized。上面我们提到过volatile具有内存可见性,但不具有原子性,而synchronized实际是上能够实现原子性的。这一点是volatile做不到的,也是这种场景下volatile无法代替synchronized。
这一点就不举例了,主要知道什么是原子性和非原子性即可自行实验了。如:a += b
就一个非原子性操作。
三、总结
- 简单的了解了volatile的用法;
- 进一步了解内存可见性和synchronized实现原理;
- volatile与synchronized的差异,以及可代替场景;
- volatile通过内存可见性实现同步,即线程A操作了被volatile修饰的变量之后,线程B立马可能读到线程A的修改结果。
我的另外一篇文章也有介绍:http://www.cnblogs.com/xuzekun/p/7426713.html
3.JUC之volatile的更多相关文章
- volatile关键字与内存可见性&原子变量与CAS算法
1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...
- 【Java_多线程并发编程】JUC原子类——原子类中的volatile变量和CAS函数
JUC中的原子类是依靠volatile变量和Unsafe类中的CAS函数实现的. 1. volatile变量的特性 内存可见性(当一个线程修改volatile变量的值后,另一个线程就可以实时看到此变量 ...
- 【JUC系列第一篇】-Volatile关键字及内存可见性
作者:毕来生 微信:878799579 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1.如果一个变量被volat ...
- JUC整理笔记二之聊聊volatile
要想学好JUC,还得先了解 volatile 这个关键字.了解 volatile ,我们从一个例子开始吧. 本文不会很详细去说java内存模型,只是很简单地学习一下volatile 一个例子 pack ...
- JUC源码学习笔记4——原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法
JUC源码学习笔记4--原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法 volatile的原理和内存屏障参考<Java并发编程的艺术> 原子类源码基于JDK8 ...
- JUC回顾之-volatile的原理和使用
1.计算机内存模型的相关概念 计算机在执行程序时,每条指令都是在CPU中执行的,在指令的执行过程中,涉及到数据的读取和写入.由于程序在运行的过程中数据是放在"主存"中的, 由于数据 ...
- (一)juc线程高级特性——volatile / CAS算法 / ConcurrentHashMap
1. volatile 关键字与内存可见性 原文地址: https://www.cnblogs.com/zjfjava/category/979088.html 内存可见性(Memory Visibi ...
- JUC(一):volatile关键字
volatile是什么 volatile是java虚拟机提供的轻量级同步机制,它包含三种特性: 保证可见性:只要主内存中变量做出修改,其余线程马上会感知到变量的修改. package com.ch ...
- JUC 并发编程--05, Volatile关键字特性: 可见性, 不保证原子性,禁止指令重排, 代码证明过程. CAS了解么 , ABA怎么解决, 手写自旋锁和死锁
问: 了解volatile关键字么? 答: 他是java 的关键字, 保证可见性, 不保证原子性, 禁止指令重排 问: 你说的这三个特性, 能写代码证明么? 答: .... 问: 听说过 CAS么 他 ...
随机推荐
- 001——Angular环境搭建、运行项目、搭建项目
1.安装node.js 和cnpm 2.cnpm install -g @angular/cli 安装angular脚手架: 3.ng new angulardemo cd angulardemo ...
- C# 实现生产者消费者队列 (转)
按语:按照下面文档,测试成功: https://www.cnblogs.com/samgk/p/4772806.html 开发过程中经常会碰到这样的场景:需要从一个地方获取一些数据,然后处理数据并将其 ...
- Android Butterknife使用方法总结 IOC框架
前言: ButterKnife是一个专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤.是大神J ...
- PBU流速权
PBU概念 PBU是“Participant Business Unit”的英文缩写,中文全称是“参与者交易业务单元”. 在新版交易规则中对此有定义:“参与者交易业务单元”是指交易参与人据此参与本所证 ...
- 解决no module named setuptools
To install setuptools on Debian: sudo apt-get install python-setuptools For Python 3.x: sudo apt-get ...
- easyui datagrid里的toobar按钮隐藏、显示、禁用等方式的实现
easyui datagrid里的toobar按钮隐藏.显示.禁用等方式的实现 //隐藏第一个按钮 $('div.datagrid-toolbar a').eq(0).hide(); //隐藏第一条分 ...
- __proto__和prototype的一些理解
var Person = function(name) { this.name = name; } var p = new Person(); new操作符的操作是 var p = {} p.__pr ...
- Web调试利器fiddler(转)
http://blog.chinaunix.net/uid-27105712-id-3738821.html
- 【GStreamer开发】GStreamer基础教程16——平台相关的element
目标 虽然GStreamer是跨平台的framework,但不是所有的element都是在所有平台下都有的.比如,音频和视频的sink都非常依赖于当前的window系统,根据当前的平台需要选择不同的e ...
- request.GET、request.POST、request.body(持续更新)
1.request.GET: print(request.GET) # <QueryDict: {'page' : ['5'], 'id__gt' : ['4']}> print(requ ...