java多线程之CAS

CAS操作
在java中可以通过CAS操作来实现操作的原子性。cas即compare and set的缩写。JVM中的CAS操作利用了处理器提供的CMPXCHG指令实现。自旋CAS实现的基本思路就是循环进行CAS操作直到成功为止。下面的代码展示的是如何通过CAS算法来实现线程同步:

package chapter02;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class CAS {

    //使用java concurrent包中的AtomicInteger类来实现CAS操作
    private AtomicInteger atomic = new AtomicInteger(0);
    //非线程安全的变量i
    private int i = 0;

    public static void main(String args[]) {
        final CAS cas = new CAS();
        List<Thread> ts = new ArrayList<Thread>(600);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int j=0;j<10000;j++){
                        cas.count();
                        cas.safeCount();
                    }
                }
            });

            ts.add(t);
        }

        for(Thread t :ts){
            t.start();
        }

        for(Thread t:ts){
            try{
                t.join();
            }catch(Exception e){
                e.printStackTrace();
            }
        }

        System.out.println("unsafe"+cas.i);
        System.out.println("safe"+cas.atomic.get());
        System.out.println(System.currentTimeMillis()-start);
    }

    //线程安全的Count方法
    private void safeCount() {
        for (;;) {
            //atomic的get()方法获取volatile变量value
            int i = atomic.get();
            //如果设置成功,则获得运行权,否则所有的线程都通过自旋的方法获取执行权
            boolean suc = atomic.compareAndSet(i, ++i);
            if (suc) {
                break;
            }
        }
    }

    //非线程安全的count方法
    private void count() {
        i++;
    }
}

上面的代码运行结构为:
unsafe834081
safe1000000
87

CAS原理:
通过查看AtomicInteger的源码可知,
`private volatile int value;

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}`
通过申明一个volatile (内存锁定,同一时刻只有一个线程可以修改内存值)类型的变量,再加上unsafe.compareAndSwapInt的方法,来保证实现线程同步的。

缺点:
1、ABA问题
CAS操作容易导致ABA问题,也就是在做a++之间,a可能被多个线程修改过了,只不过回到了最初的值,这时CAS会认为a的值没有变。a在外面逛了一圈回来,你能保证它没有做任何坏事,不能!!也许它讨闲,把b的值减了一下,把c的值加了一下等等,更有甚者如果a是一个对象,这个对象有可能是新创建出来的,a是一个引用呢情况又如何,所以这里面还是存在着很多问题的,解决ABA问题的方法有很多,可以考虑增加一个修改计数,只有修改计数不变的且a值不变的情况下才做a++,也可以考虑引入版本号,当版本号相同时才做a++操作等,这和事务原子性处理有点类似!
2、比较花费CPU资源,即使没有任何争用也会做一些无用功。
3、会增加程序测试的复杂度,稍不注意就会出现问题。

总结:
可以用CAS在无锁的情况下实现原子操作,但要明确应用场合,非常简单的操作且又不想引入锁可以考虑使用CAS操作,当想要非阻塞地完成某一操作也可以考虑CAS。不推荐在复杂操作中引入CAS,会使程序可读性变差,且难以测试,同时会出现ABA问题。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值