volatile保证可见性

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1)保证了不同线程对这个变量进行操作的可见性,即一个线程修改了某个变量的值,这新值对其它线程来说是立即可见的

  2)禁止进行指令重排序

 volatile不能确保原子性

 在访问volatile变量时,不会执行加锁操作,因此也就不会执行线程阻塞。所以volatile变量是一种比sychhronized关键字更轻量级的同步机制

 关于这一点,可看个例子:

public class VolatileDemo {

    private volatile int number = ;

    public int getNumber() {
return this.number;
} public void add() {
this.number++;
} public static void main(String[] args) {
final VolatileDemo demo = new VolatileDemo();
for (int i = ; i < ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
demo.add();
}
}).start();
} // 如果还有子线程在运行,主线程就让出CPU资源
// 直到所有的子线程都运行完了,主线程再继续往下执行
while (Thread.activeCount() > ) {
Thread.yield();
}
System.out.println("number:" + demo.getNumber());
} }

大家想一下这段程序的输出结果是多少?也许有些朋友认为是500,但是事实上运行它会发现偶尔会出现小于500的值。如果在number++前,加一个Thread.sleep(),效果更明显

接下来,我们分析一下为啥会出现这种情况:

假如某个时刻变量number=5

1. 线程A读取number的值,然后阻塞

2. 线程B读取number的值

3. 线程B执行加1操作

4. 线程B写入最新的number的值(6)到主内存中。此时线程A工作内存中number还是5

5. 线程A执行加1操作

6. 线程A写入最新的number值(6)到主内存中

两个线程分别进行了一次自增操作后,number只增加了1。

根源就在自增操作不是原子性操作,而volatile也无法保证对变量的任何操作都是原子性

解决方案:可以通过synchronized或lock,进行加锁,来保证操作的原子性。也可以通过AtomicInteger。

具体例子:

    public void add2() {
// 加上synchronized后,就可以保证原子性
synchronized (this) {
this.number++;
}
} public void add3() {
// 加上lock后,保证原子性
lock.lock();
try {
this.number++;
} finally {
lock.unlock();
}
} //AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减
private AtomicInteger count = new AtomicInteger(); public void add4() {
count.getAndIncrement();
}

volatile的适用场景:

  1、对变量的写入操作不依赖其当前值(如 number++ 、count = count * 5等)

  2、该变量没有包含在具有其它变量的不变式中

3、volatile的一个重要作用就是和CAS结合,保证了原子性,详细的可以参见java.util.concurrent.atomic包下的类,比如AtomicInteger

参考资料:http://www.importnew.com/24082.html

  

volatile特性的更多相关文章

  1. volatile特性及内存语义

    1.volatile变量自身具有下列特性:·可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入.·原子性:对任意单个volatile变量的读/写具有原子 ...

  2. java - jmm之volatile特性

    volatile是什么? volatile是JVM提供的一种轻量级的同步机制,其具有三个特性. 保证可见性 不保证原子性 禁止指令重排 保证可见性 JMM(java memory model)中文翻译 ...

  3. volatile关键字的特性及证明

    volatile是java虚拟机提供的轻量级的同步机制 JMM(Java内存模型)是围绕着并发编程中原子性.可见性.有序性这三个特征来建立的 原子性:一个操作或多个操作要么全部执行完成且执行过程不被中 ...

  4. volatile的特性

    volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...

  5. java内存模型-volatile

    volatile 的特性 当我们声明共享变量为 volatile 后,对这个变量的读/写将会很特别.理解 volatile 特性的一个好方法是:把对 volatile 变量的单个读/写,看成是使用同一 ...

  6. java 中的volatile

    本博客摘录自   http://www.infoq.com/cn/articles/java-memory-model-4/ 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解 ...

  7. synchronized同步块和volatile同步变量

    Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...

  8. 深入理解Java内存模型(四)——volatile

    volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...

  9. 【转】深入理解Java内存模型(四)——volatile

    volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...

随机推荐

  1. .net加密web.config文件

    这篇文章我将介绍如何利用ASP.NET来加密和解密Web.config中连接字符串,之前只写了第二种方式,现在将两种方式都写出来,供大家参考.不管使用哪种方式我们在程序中都不需要写任何代码来解密连接字 ...

  2. [ASP.NET].NET逻辑分层架构总结

    一.基础知识准备: 1.层的原则: (1)每一层以接口方式供上层调用. (2)上层只能调用下层. (3)依赖分为松散交互和严格交互两种. 2.业务逻辑分类: (1)应用逻辑. (2)领域逻辑. 3.采 ...

  3. Windows Phone中解决多模块多程序集之间相互循环引用的问题一种思路

    Windows Phone中解决多模块多程序集之间相互循环引用的问题一种思路 那就是利用mvvmlight中的messager组件(可单独提取出),制作双向的一个消息发送.通过公共的类的定义,来传递数 ...

  4. hdu 4325 Flowers(区间离散化)

    http://acm.hdu.edu.cn/showproblem.php?pid=4325 Flowers Time Limit: 4000/2000 MS (Java/Others)    Mem ...

  5. hashlib 和loggin模块

    1.摘要算法hashlib 1. md5加密 #1. 摘要算法 #md5加密算法 32位 import hashlib username ="alex" md5_obj =hash ...

  6. django-ORM相关代码及其sql执行次数

    1.普通情况:通过log可以看出,这种情况下,访问了1次数据库 def test(request): """测试连表""" users = ...

  7. Windows下TensorFlow安装指南(图文版)

    随着深度学习概念火起来,TensorFlow也跟着成为业界流行的深度学习框架.它采用CPU+GPU的并行计算模式,使得神经网络可以有效的并行计算,从以前的三层网络到现在的深层网络,深度学习+tenso ...

  8. (samba启动失败)smb.service: main process exited, code=exited, status=1/FAILURE

    按照指示,前往:journalctl -xe 没什么发现,搜的时候有人说也可以查看 journalctl -r 打出来之后我也看不出什么门道来 又看到有人说 smb 方面可以看看 testparm 我 ...

  9. 使用 find 命令实现高级排除需求

    使用 find 命令实现高级排除需求 Linked 关于 find 命令,本博客介绍过 atime,ctime,mtime 介绍过 --exec 参数. 介绍这些的基本需求是进行文件管理.事实上,基于 ...

  10. 解决chrome无法启用印象笔记-剪藏功能

        新版Chrome浏览器安全的问题,导致从印象笔记官网下载的rxs(crx)文件无法直接通过drap&drop功能添加功能块.可以将rxs(crx)文件后缀名改成rar格式,然后解压,通 ...