volatile特性
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特性的更多相关文章
- volatile特性及内存语义
1.volatile变量自身具有下列特性:·可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入.·原子性:对任意单个volatile变量的读/写具有原子 ...
- java - jmm之volatile特性
volatile是什么? volatile是JVM提供的一种轻量级的同步机制,其具有三个特性. 保证可见性 不保证原子性 禁止指令重排 保证可见性 JMM(java memory model)中文翻译 ...
- volatile关键字的特性及证明
volatile是java虚拟机提供的轻量级的同步机制 JMM(Java内存模型)是围绕着并发编程中原子性.可见性.有序性这三个特征来建立的 原子性:一个操作或多个操作要么全部执行完成且执行过程不被中 ...
- volatile的特性
volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...
- java内存模型-volatile
volatile 的特性 当我们声明共享变量为 volatile 后,对这个变量的读/写将会很特别.理解 volatile 特性的一个好方法是:把对 volatile 变量的单个读/写,看成是使用同一 ...
- java 中的volatile
本博客摘录自 http://www.infoq.com/cn/articles/java-memory-model-4/ 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解 ...
- synchronized同步块和volatile同步变量
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...
- 深入理解Java内存模型(四)——volatile
volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...
- 【转】深入理解Java内存模型(四)——volatile
volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...
随机推荐
- artdialog(4.1.7)弹出框
artDialog弹出框 <link href="/js/artDialog/skins/default.css" rel="stylesheet" /& ...
- c# is 和 as 的区别和使用
1:is 是判断类型,用于检查对象是否与给定类型兼容,不成功则不会抛出异常,如果兼容则返回true,如果不兼容则返回false.在进行类型转换之前用 f (P_obj is System.String ...
- 使用filter进行登录验证,并解决多次重定向问题
最近在做关于filter登录验证的功能,防止未登录的用户直接通过地址进入系统 LoginFilter类:继承Filter接口 package com.ss.filter; import java.io ...
- C++实现-特征码遍历
#include <stdio.h> #include <stdlib.h> #include <windows.h> union Base { DWORD add ...
- 盗墓笔记—阿里旺旺ActiveX控件imageMan.dll栈溢出漏洞研究
本文作者:i春秋作家——cq5f7a075d 也许现在还研究Activex就是挖坟,但是呢,笔者是摸金校尉,挖坟,呸!盗墓是笔者的本职工作. 额,不扯了,本次研究的是阿里旺旺ActiveX控件imag ...
- (samba启动失败)smb.service: main process exited, code=exited, status=1/FAILURE
按照指示,前往:journalctl -xe 没什么发现,搜的时候有人说也可以查看 journalctl -r 打出来之后我也看不出什么门道来 又看到有人说 smb 方面可以看看 testparm 我 ...
- webpack快速入门——CSS文件打包
1.在src下新建css文件,在css文件下新建index.css文件,输入以下代码 body{ background:pink; color:yellowgreen; } 2.css建立好后,需要引 ...
- java验证身份证合理性
package com.tiantian.util; import java.util.Calendar;import java.util.HashMap;import java.util.Map;i ...
- Tomcat几种出错方法
1. Several ports (8005, 8089, 8009) required by Tomcat v8.0 Server at localhost are already in use. ...
- 初识PHP之php运行流程及原理(一)
初识PHP一.用脚本命令行运行php(1)打开cmd.exe(winkey+R)(2)找到php.exe(拖进cmd即可)(3)输入命令php.exe -f "文件实际路径"注:运 ...