原文链接: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就一个非原子性操作。

三、总结

  1. 简单的了解了volatile的用法;
  2. 进一步了解内存可见性和synchronized实现原理;
  3. volatile与synchronized的差异,以及可代替场景;
  4. volatile通过内存可见性实现同步,即线程A操作了被volatile修饰的变量之后,线程B立马可能读到线程A的修改结果。

我的另外一篇文章也有介绍:http://www.cnblogs.com/xuzekun/p/7426713.html

3.JUC之volatile的更多相关文章

  1. volatile关键字与内存可见性&原子变量与CAS算法

    1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...

  2. 【Java_多线程并发编程】JUC原子类——原子类中的volatile变量和CAS函数

    JUC中的原子类是依靠volatile变量和Unsafe类中的CAS函数实现的. 1. volatile变量的特性 内存可见性(当一个线程修改volatile变量的值后,另一个线程就可以实时看到此变量 ...

  3. 【JUC系列第一篇】-Volatile关键字及内存可见性

    作者:毕来生 微信:878799579 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1.如果一个变量被volat ...

  4. JUC整理笔记二之聊聊volatile

    要想学好JUC,还得先了解 volatile 这个关键字.了解 volatile ,我们从一个例子开始吧. 本文不会很详细去说java内存模型,只是很简单地学习一下volatile 一个例子 pack ...

  5. JUC源码学习笔记4——原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法

    JUC源码学习笔记4--原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法 volatile的原理和内存屏障参考<Java并发编程的艺术> 原子类源码基于JDK8 ...

  6. JUC回顾之-volatile的原理和使用

    1.计算机内存模型的相关概念 计算机在执行程序时,每条指令都是在CPU中执行的,在指令的执行过程中,涉及到数据的读取和写入.由于程序在运行的过程中数据是放在"主存"中的, 由于数据 ...

  7. (一)juc线程高级特性——volatile / CAS算法 / ConcurrentHashMap

    1. volatile 关键字与内存可见性 原文地址: https://www.cnblogs.com/zjfjava/category/979088.html 内存可见性(Memory Visibi ...

  8. JUC(一):volatile关键字

    volatile是什么 ​ volatile是java虚拟机提供的轻量级同步机制,它包含三种特性: 保证可见性:只要主内存中变量做出修改,其余线程马上会感知到变量的修改. package com.ch ...

  9. JUC 并发编程--05, Volatile关键字特性: 可见性, 不保证原子性,禁止指令重排, 代码证明过程. CAS了解么 , ABA怎么解决, 手写自旋锁和死锁

    问: 了解volatile关键字么? 答: 他是java 的关键字, 保证可见性, 不保证原子性, 禁止指令重排 问: 你说的这三个特性, 能写代码证明么? 答: .... 问: 听说过 CAS么 他 ...

随机推荐

  1. Fastjson 序列化与反序列化

    JSON这个类是fastjson API的入口,主要的功能都通过这个类提供. 序列化API // 将Java对象序列化为JSON字符串,支持各种各种Java基本类型和JavaBean public s ...

  2. LeetCode_235. Lowest Common Ancestor of a Binary Search Tree

    235. Lowest Common Ancestor of a Binary Search Tree Easy Given a binary search tree (BST), find the ...

  3. POJ 2584 T-Shirt Gumbo 二分图的多重匹配

    题目链接:http://poj.org/problem?id=2584 题目大意:有SMLXT五种T恤型号,有N个人,每个人有一个可选的型号区间,你现在要发给N个人每人一条他可以选择的型号的T恤,问能 ...

  4. MySQL之忘记root重置方法

    参考:https://help.aliyun.com/knowledge_detail/42520.html MySQL忘记了root登录密码需要重置 1,修改配置文件 一般配置文件路径为/etc/m ...

  5. STM32驱动模数转换芯片ADS1120(基础知识篇)第1篇

    1. 先看下ADS1120的结构图,ADS1120是个比较奇葩的ADC模数转换器,因为比较适用于热电阻之类的温度采集器.看下图,有个MUX多路复用器,应该是选择两个差分信号去测试,通过输入多路复用器 ...

  6. 06点睛Spring MVC 4.1-文件上传

    6.1 文件上传 在控制器参数使用@RequestParam("file") MultipartFile file接受单个文件上传; 在控制器参数使用@RequestParam(& ...

  7. 微服务Consul系列之集群搭建

    在上一篇中讲解了Consul的安装.部署.基本的使用,使得大家有一个基本的了解,本节开始重点Consul集群搭建,官方推荐3-5台Server,因为在异常处理中,如果出现Leader挂了,只要有超过一 ...

  8. 【GStreamer开发】GStreamer播放教程08——视频解码的硬件加速

    目标 视频的硬件解码近来发展非常快速,尤其是在低功耗的设备上.本教程会讲述一些硬件加速的背景知识并解释一下GStreamer是怎么做的. 悄悄告诉你,如果设置正确地话,我们什么也不用做,GStream ...

  9. 莫比乌斯反演求LCM的另一种做法

    一个经典问题 求 \[ \sum_{k=1}^n\mathbb{lcm}(k,n) \] 一般的做法是使用\(\varphi(n)\)函数. 不经典的做法 \[ \begin{align*} \sum ...

  10. idea查看接口及类的关系继承(UML)图

    选中接口或类 显示结果: 如果需要添加其他的接口或类:点击右键 添加需要的接口或类: 显示结果: