原子变量 CAS算法
一、CAS算法
public static void main(String[] args) {
AtomicDemo demo = new AtomicDemo();
for(int i=0;i<=10;i++){
new Thread(demo).start();;
}
}
class AtomicDemo implements Runnable {
private int number = 0;
public void run() {
//synchronized (AtomicDemo.class) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(number++);
//}
}
}
就会出现 0 1 2 2 2 3 4 8 7 6 5
控制台打印就会出现多线程问题 或者说出现原子性问题
1. 比如 i++问题
i=10;
i=i++;i的结果是10
在计算机的底层 临时变量temp 有三部操作“读-改-写” 可以通过javap 反编译 看他是如何运行
int temp = i;
i=i+1; i++可以看成 i=i+1
i=temp; 先temp值赋给i 依然是10 然后再是
可以看作 j=i++ temp=i; 然后 i是自增1, i为10值赋给j
对上述number 定义volatile 内存可见性,也无法保证线程安全问题,因为线程1与线程2再各自独立缓存中进行number++操作时,三个步骤读 改 写,先将主存中的number读到线程的工资内存中,number在加1,然后在将number值写入主存中,不具备原子性(原子特性是不可在分割的)
处理使用原子变量
二、原子变量:jdk1.5 后java.util.concurrent.atomic 包下提供了常用的原子
1. volatile保证了内存可见性(Atomic类中属性用volatile修饰)
2. 用CAS(Compare And Swap)算法保证数据的原子性
CAS算法是硬件对于并发操作共享数据的支持 JVM支持CAS算法,JVM底层大量实现CAS算法
CAS算法包含了三个操作数:
内存值 V:从主存中取出值
预估值 A:对于非原子性的操作,再进行下一次计算操作之前,会再次读取主存中的值
更新值 B:根据具体的逻辑,有待跟新的值
条件满足:当且仅当V==A时,那么把B值赋给V(B=V);否则将不做任何操作
线程1 首先读取主存中的共享资源值 V值为0(V=0),在进行替换时候,需要再读取主存中的旧值 A值为0(A=0),经过number++运算B更新值1。
当线程1操作时,此时线程2将主存中的值读取V=0(线程1未进行写入主存的操作),在替换时,线程1对主存中的数据进行写入(此时number=1,V=A成立将B值写入),再对主存的旧值再进行读取A为1(A=1),B的值相较于V=0进行number++运行B=1。此时V为0,A为1 V!=A,不做任何操作
如果多个线程并发的对主存的数据进行修改时有且只有一个线程会成功,其它线程都失败。
CAS效率比锁效率高,因为CAS当线程失败以后,CPU不会放弃执行权,紧接着线程会再去尝试更新,所以要不原来同步所的效率高很多
class AtomicDemo implements Runnable {
//private volatile int number = 0;
private AtomicInteger number = new AtomicInteger();
public void run() {
//synchronized (AtomicDemo.class) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( number.getAndIncrement() );
//}
}
}
简单的模拟CAS算法
public class TestCompareAndSwap {
//简单的模拟CAS算法
public static void main(String[] args) {
final CompareAndSwap cas = new CompareAndSwap();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int expectValue = cas.get();//读取主存中的值V
boolean b = cas.compareAndSet(expectValue, (int)(Math.random()*104));
System.out.println(b);
}
}).start();
}
}
}
class CompareAndSwap{
//主存中的共享资源
private int value;
public synchronized int get(){//获取主存的值
return value;
}
//比较
public synchronized int compareAndSwap(int expectValue,int newValue){
int oldValue = value;//在比较之前再获取主存值
if(oldValue == expectValue){
this.value = newValue;
}
return oldValue;
}
//设置
public synchronized boolean compareAndSet(int expectValue,int newValue){
return expectValue == compareAndSwap(expectValue, newValue);
}
}
原子性理解
volatile关键字的深入理解 http://www.importnew.com/24082.html