Java线程-volatile不能保证原子性
下面是一共通过volatile实现原子性的例子:
通过建立100个线程,计算number这个变量最后的结果。
package com.Sychronized; public class VolatileDemo { private volatile int number=0;
public int getNumber()
{
return this.number;
}
public void increase()
{
this.number++;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
final VolatileDemo volDemo=new VolatileDemo();
for(int i=0;i<100;i++)
{
new Thread(new Runnable() {
@Override
public void run() {
volDemo.increase();
}
}).start();
} //如果还有子线程在运行,主线程就让出CPU资源
//直到所有的子线程都运行完了,主线程再继续往下执行
while(Thread.activeCount()>1)
{
Thread.yield();
} System.out.println("number:"+volDemo.getNumber());
} }
运行结果:
发现有几种结果:
造成这个结果的原因就是,volatile关键字具有可见性,number++实际上有三步操作,但是不具备原子性。
程序分析:
number++包含三步操作:1,读取number的值,2,number的值加,3,写入number的值给number变量。
假如当前nubmer=5
1,线程A读取number的值
2,线程B读取number的值
3,线程B执行加1操作
4,线程B写入最新的number的值。
此时:主内存:number=6,线程B工作内存:number=6,线程A工作内存:number=5。
5,线程A执行加1操作
6,线程A写入最新的number值。
两次number++操作,只增加了1。
解决方案:
1,使用synchronized关键字
2,使用ReentrantLock(java.until.concurrent.locks包下)
3,使用AtomicInterger(java.util.concurrent.atomic包下)
可以看这个文章:
Java并发编程:volatile关键字解析:http://www.importnew.com/18126.html
第一种:
private int number=0;
public int getNumber()
{
return this.number;
}
public synchronized void increase()
{
this.number++;
}
或者:
private int number=0;
public int getNumber()
{
return this.number;
}
public void increase()
{
synchronized(this)
{
this.number++;
}
}
第二种:
对执行加锁处理的地方使用 try finally。。操作,在finally里面,执行lock.unlock释放锁。
private int number=0;
private Lock lock = new ReentrantLock();
public int getNumber()
{
return this.number;
}
public void increase()
{
lock.lock();
try {
this.number++;
}finally {
lock.unlock();
}
}
volatile使用场合
synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。通常来说,使用volatile必须具备以下2个条件:
1)对变量的写操作不依赖于当前值
- .不满足:number++,count=count*5等
- .满足:boolean变量,记录温度变化的变量等
2)该变量没有包含在具有其他变量的不变式中
- 不满足:不变式:low<up
.实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
事实上,我的理解就是上面的2个条件需要保证操作是原子性操作,才能保证使用volatile关键字的程序在并发时能够正确执行。
volatile使用场景
(同样摘自文章Java并发编程:volatile关键字解析:http://www.importnew.com/18126.html)
1.状态标记量
volatile boolean flag = false; while(!flag){
doSomething();
} public void setFlag() {
flag = true;
}
volatile boolean inited = false;
//线程1:
context = loadContext();
inited = true; //线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);
2.double check
class Singleton{
private volatile static Singleton instance = null; private Singleton() { } public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}
synchronized和volatile比较
- volatile不需要加锁,比synchronized更轻量级,不会阻塞线程;
- 从内存可见性角度讲,volatile读相当于加锁,volatile写相当于解锁。
- synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性。
Java线程-volatile不能保证原子性的更多相关文章
- Java并发编程之验证volatile不能保证原子性
Java并发编程之验证volatile不能保证原子性 通过系列文章的学习,凯哥已经介绍了volatile的三大特性.1:保证可见性 2:不保证原子性 3:保证顺序.那么怎么来验证可见性呢?本文凯哥(凯 ...
- 为什么volatile不能保证原子性而Atomic可以?
在上篇<非阻塞同步算法与CAS(Compare and Swap)无锁算法>中讲到在Java中long赋值不是原子操作,因为先写32位,再写后32位,分两步操作,而AtomicLong赋值 ...
- volatile之一--volatile不能保证原子性
Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这 ...
- 为什么volatile不能保证原子性?
为什么volatile能替代简单的锁,却不能保证原子性?这里面涉及volatile,是java中的一个我觉得这个词在Java规范中从未被解释清楚的神奇关键词,在Sun的JDK官方文档是这样形容vola ...
- Volatile不保证原子性(二)
Volatile不保证原子性 前言 通过前面对JMM的介绍,我们知道,各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存进行操作后在写回到主内存中的. 这就可能存在一个线程AAA修改 ...
- 【转】为什么volatile不能保证原子性而Atomic可以?
直接上好文链接!!! 为什么volatile不能保证原子性而Atomic可以?
- Java中volatile如何保证long和double的原子性操作
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11426473.html 关键字volatile的主要作用是使变量在多个线程间可见,但无法保证原子性,对 ...
- java中volatile不能保证线程安全
今天打了打代码研究了一下java的volatile关键字到底能不能保证线程安全,经过实践,volatile是不能保证线程安全的,它只是保证了数据的可见性,不会再缓存,每个线程都是从主存中读到的数据,而 ...
- java线程--volatile实现可见性
volatile关键字: 1)能够保证volatile变量的可见性 2)不能保证volatile变量复杂操作的原子性. volatile如何实现内存可见性: 深入来说:通过加入内存屏障和禁止重排序优化 ...
随机推荐
- Makefile-命令前的@和-符号
Makefile中命令前的@和-符号如果make执行的命令前面加了@字符,则不显示命令本身而只显示它的结果; Android中会定义某个变量等于@,例如 hide:= @ 通常make执行的命令如果出 ...
- PHP -- 8个必备的PHP功能开发
原文出处:http://www.codeceo.com/8-php-functions.html 做过PHP开发的程序员应该清楚,PHP中有很多内置的功能,掌握了它们,可以帮助你在做PHP开发时更加得 ...
- Educational Codeforces Round 12 C. Simple Strings 贪心
C. Simple Strings 题目连接: http://www.codeforces.com/contest/665/problem/C Description zscoder loves si ...
- python gensim的第一次试用
参考于 http://blog.csdn.net/xiaoquantouer/article/details/53583980 有一个地方很重要,一定要安装anaconda,安装库简直不要太方便. 先 ...
- kali 执行apt-get upgrade后,终端无法打开的解决办法
今天在kali执行apt-get upgrade命令后,reboot启动,发现进入界面终端无法开启 一波百度,google发现大概应该是语言的配置问题,因为最开始安装kali的时候是选择中文,可能up ...
- mysql select语句执行顺序
SELECT语句定义 一个完成的SELECT语句包含可选的几个子句. SELECT语句的定义如下: <SELECT clause> [<FROM clause&g ...
- End of Life check fails with NullPointerException
Checks if the running version of JIRA is approaching, or has reached End of Life. Details Type: Bug ...
- Gulp插件less的使用
1.创建:gulpfile.js var gulp = require('gulp'), less = require('gulp-less'); gulp.task('default', funct ...
- Go:《Go语言 云动力》
背景 中秋快速的读了一遍<Go语言 云动力>,对Go有一下几点感觉: 在静态类型和动态类型之间取得了非常好的平衡,隐式接口实现会被后续的语言借鉴(希望C#能借鉴一下). 缺乏异常处理机制, ...
- (转)Sql Server 快速查看表结构(表描述及字段说明)
--表描述 SELECT tbs.name 表名,ds.value 描述 FROM sys.extended_properties ds LEFT JOIN sysobjects tbs ON ds. ...