唐僧喜欢小龙女

导航

Java中CAS方法的学习整理

1、引出CAS的需求

/**
 *
 *
 *  需求:开发一个网站需要对用户量进行统计,用户每发送一个请求访问量就加1,如何实现
 *       模拟100个人同时访问,每个人发起10次请求,统计结果应该是1000次。
 *
 *
 */

2、代码实现

public class Zdycas {

    private static volatile int count = 0;

    public static void main(String[] args) throws InterruptedException{
        Long start = System.currentTimeMillis();
        System.out.println("开始时间是"+start);
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for(int j = 0;j< 10; j++){
            new Thread(()->{

                try{
                    for (int i = 0; i < 100; i++) {
                        getCount();
                    }
                }catch (Exception e){

                }finally {
                    countDownLatch.countDown();
                }
            }).start();
        }

        countDownLatch.await();

        Long end =  System.currentTimeMillis();
        System.out.println("结束时间是"+end);


        /**
         *
         * 1、测试的结果是count的值很难达到1000
         *     原因:count++ 不是原子性操作分为三部分
         *              (1)把count 赋值给A A=count
         *              (2)A+1 赋值给B
         *             (3)把B赋值给count
         *          volatile 能保证内存可见行以及禁止指令重排,但是保证不了count++变成一个原子性的操作。
         * 2、使用synchronized、可重入锁、原子锁等方式
         *      synchronized 锁效率太低了
         * 3、自定义一个cas方法
         *     (1)cas定义:CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换。
         *     (2)compareAndSwap()方法:CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。
         *       更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。
         * 4、CAS存在的问题
         *    (1)CPU开销较大:在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,
         *        会给CPU带来很大的压力。比如 getCount()方法中的while循环
         *    (2)不能保证代码块的原子性:CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。
         *        比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了
         *    (3)ABA问题:这是CAS机制最大的问题所在。
         * 5、java cas 常用的api
         *     public final native boolean compareAndSwapObject(Object var1,long var2,Object var4,Object var5)
         *     public final native boolean compareAndSwapInt(Object var1,long var2,int var4,int var5)
         *     public final native boolean compareAndSwapLong(Object var1,long var2,Long var4,Long var6)
         *
         *     var1:表示要操作的对象
         *     var2:表示要操作对象中属性的偏移值
         *     var4:表示需要修改的数据的期望值
         *     var5:表示需要修改的新值
         *
         *
         * 6、java cas 的原理是什么
         *      CAS通过调用JNI的代码实现,JNI :java native interface,它允许java通过调用它来调用其他语言。而comapreAndSwapxxx
         *      系列方法就是就是借助C语言来调用cpu底层指令实现的比较和替换。这些cpu的底层指令是原子性的。
         *
         */

        System.out.println(count+"main");
        System.out.println("花费的时间是"+ (end-start));
    }


      //这个是原来的getCount 方法
//    public static  void getCount() throws InterruptedException{
//        TimeUnit.MILLISECONDS.sleep(5);
//        count++;
//    }

    public static  void getCount() throws InterruptedException{
        TimeUnit.MILLISECONDS.sleep(5);
//        count++;
        int expectCount;
        //这里是一个自旋锁
        while (! compareAndSwap(expectCount = count,expectCount + 1)){}

    }

    //自定义的cas方法。

    /**
     *
     *
     *
     * @param expectCount
     * @param newCount
     * @return
     */
    public static synchronized  boolean compareAndSwap(int expectCount,int newCount){
        //判断当前线程的count 和期望的count(expectCount)是否一致
        if(count == expectCount){
            count =  newCount;
            return true;
        }
        return false;


        //这里使用java自带的方式
        // return atomicInteger.compareAndSet(expectCount,newCount);
    }

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2021-10-17 11:06  与时具进&不忘初心  阅读(159)  评论(0编辑  收藏  举报