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 1779
较水的网络流. /************************************************************** Problem: 1779 User: idy002 L ...
- 并查集--CSUOJ 1601 War
并查集的经典题目: CSUOJ 1601: War Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 247 Solved: 70[Submit][Sta ...
- Java高级架构师(一)第41节:Nginx的配置优化以及使用建议
- [转]Jquery实现页面定时跳转
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Codeforces Round #202 (Div. 1) D. Turtles DP
D. Turtles Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/547/problem/B ...
- [原]Redis使用场景及使用经验
Redis is an open source (BSD licensed), in-memory data structure store! 欢迎转载,转载请注明出处 刚刚结束一个游戏类的活动项目, ...
- IPC low/medium/high density 什么意思?
http://wiki.altium.com/pages/viewpage.action?pageId=3080344 Land Pattern Information Density Level A ...
- 面试题1:如何实现C++单例模式?
1. 软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径.设计模式中运用了面向对象编程语言的重要特性:封装.继承.多态.真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积 ...
- [c#基础]泛型集合的自定义类型排序
引用 最近总有种感觉,自己复习的进度总被项目中的问题给耽搁了,项目中遇到的问题,不总结又不行,只能将复习基础方面的东西放后再放后.一直没研究过太深奥的东西,过去一年一直在基础上打转,写代码,反编译,不 ...
- Alert Messager
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...