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. telerik:RadGrid 表格中删除数据

    <telerik:RadGrid OnItemCommand=" Height="490px" Culture="zh-CN" CssClass ...

  2. 使用n g r o k将本地主机URL暴露给互联网

    在本地开发对接第三方服务的时候,对方有的时候会要求我们提供一个线上的URL地址.例如微信登录 1.下载ngrok https://ngrok.com/download 顺便注册一个账号(使用GitHu ...

  3. Python廖雪峰学习笔记——单元测试

    定义:对一个模块.一个类.一个函数进行进行正确性检验的测试性工作.当我们对函数或者模块等进行修改时,单元测试就显得尤为重要. 单元测试 = 测试用例(用来测试的数据)+测试模块

  4. bootstrap 常用class(不定时更新)

    1,字体居右 text-right 2,字体居中 text-center

  5. poj2479 Maximum sum

    http://poj.org/problem?id=2479 题目大意:给定一组n个整数:a ={a1, a2,…,我们定义一个函数d(a)如下: 你的任务是计算d(A).输入由T(<=30)测 ...

  6. Python中线程与互斥锁

    了解之前我们先了解一下什么是多任务? 概念: 几个不同的事件在同时运行就是多任务, 这样的话, 我们有牵扯到了真的多任务, 假的多任务; 并行: 真的多任务, 通过电脑的核数来确定 并发: 假的多任务 ...

  7. WebStorm 最新版本激活方式

    WebStorm 最新版本激活方式:今天下载最新版本的WebStorm,发现原来的通过license server激活的方式,网上的已经失效. 找到一种最新的激活码,今天试了下,是有效的.记录下. 注 ...

  8. day 50 AJAX 初入门

    前情提要: jq 学不好,ajax   难用好, 食用先请先确保最起码的jq 能会用 https://www.cnblogs.com/baili-luoyun/p/10473518.html  jq ...

  9. 使用sqlyog连接到服务器数据库,实现可视化数据操作。(完美解决版。)《亲测!!!!》

      服务器中的表 select Host ,User ,Select_priv ,Insert_priv ,Update_priv ,Delete_priv ,Create_priv ,Drop_pr ...

  10. 【Oracle】数据泵导入导出

    数据泵 expdp导出 nohup expdp  system/******** dumpfile=lysb_20121113_%U.dmp directory=dmp_dir schemas=sco ...