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如何实现内存可见性: 深入来说:通过加入内存屏障和禁止重排序优化 ...
随机推荐
- bzoj 1143: [CTSC2008]祭祀river / 2718: [Violet 4]毕业旅行 -- 二分图匹配
1143: [CTSC2008]祭祀river Time Limit: 10 Sec Memory Limit: 162 MB Description 在遥远的东方,有一个神秘的民族,自称Y族.他们 ...
- POJ 2482 Stars in Your Window 线段树
如果按一般的思路来想,去求窗户能框住的星星,就很难想出来. 如果换一个思路,找出每颗星星能被哪些窗户框住,这题就变得非常简单了. 不妨以每个窗户的中心代表每个窗户,那么每颗星星所对应的窗户的范围即以其 ...
- 51nod 1035 最长的循环节 数学
1035 最长的循环节 题目连接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1035 Description 正整 ...
- md5加密,md5加盐加密和解密
package com.java.test; import java.security.MessageDigest; import java.security.SecureRandom; import ...
- mybatis源码分析(6)-----核心调度对象StatmentHandler
写在前面 通过上一偏文章,我们知道:mybatis 的插件开发,主要是集中在Executor(执行器),ParameterHandler(参数处理器),ResultSetHandler(结果集处理器) ...
- LM27313 (ACTIVE) 具有 30V 内部 FET 开关(采用 SOT-23 封装)的 1.6 MHz 升压转换器
The LM27313 switching regulator is a current-mode boost converter with a fixed operating frequency o ...
- 模板方法在Spring事务中的应用
事务对于我们来讲不并陌生,也是在实际应用中一直都在使用.在JDBC中,事务大致的使用结构如下: 开启事务 业务逻辑处理 提交事务 Spring只是对事务进行了扩展和封装使用,现在看看在内部它是如何工作 ...
- x64 寄存器使用
http://blog.csdn.net/cosmoslife/article/details/8771773 http://blog.csdn.net/herx1/article/details/3 ...
- Eclipse:The superclass javax.servlet.http.HttpServlet was not found on the Java Build Path
我们在用Eclipse进行Java web开发时,可能会出现这样的错误:The superclass javax.servlet.http.HttpServlet was not found on t ...
- [js插件]分享一个文章内容信息提示插件Colortip
引用 项目中需要一个信息提示的功能,就上网找了一个插件,发现colortip实现比较简单,就定了这个插件. 实现过程 官网:http://tutorialzine.com/2010/07/colort ...