CAS与ABA问题

4 篇文章 0 订阅

CAS实现原子操作的三大问题

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class Counter {
    private AtomicInteger atomicInteger = new AtomicInteger(0);
    private int i=0;
    // 非线程安全方法
    private void count(){
        i++;
    }
    // 线程安全方法
    private void safeCount(){
        for(;;){
            int i = atomicInteger.get();
            boolean succ = atomicInteger.compareAndSet(i,++i);
            if(succ)
                break;
        }
    }
    public static void main(String[] args) {

        final Counter cas = new Counter();
        List<Thread> ts = new ArrayList<Thread>(600);
        long start = System.currentTimeMillis();
        for(int j=0;j<100;j++){
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i=0;i<1000;i++){
                        //分别调用安全方法和非安全方法
                        cas.count();
//                        cas.safeCount();
                    }
                }
            });
            ts.add(t);
        }
        for(int i=0;i<ts.size();i++)
            ts.get(i).start();
        for (Thread t : ts) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(cas.i);
        System.out.println(cas.atomicInteger.get());

    }
}

分别调用安全方法和非安全方法,可以发现,调用非安全方法返回的值大部分情况下不到100000,而使用安全方法返回的值每次都准确为100000。

但是使用CAS实现原子操作可能带来三个问题

  1. ABA问题。因为CAS在比操作值得时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,中间变成B,最后又变成A,那么使用CAS进行检查时会发现值没有发生变化,但是实际上是变化了的。解决思路就是添加版本号。 JDK1.5之后,Atomic包提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
public boolean weakCompareAndSet(   
            V   expectedReference,      // 预期引用
            V   newReference,       // 新引用
            int expectedStamp,      // 预期标志
            int newStamp) {         // 新标志
        return compareAndSet(expectedReference, newReference,expectedStamp, newStamp);
    }
  1. 循环时间开销大。自旋CAS如果长时间不成功,会给CPU带来非常大的开销。
  2. 只能保证一个共享变量的原子操作。当对多个共享变量CAS操作不能保证原子性,可以把多个共享变量合并成一个共享变量来操作。或者使用加锁的方式。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值