zoukankan      html  css  js  c++  java
  • CAS(Compare And Swap) 算法

    CAS 也叫自旋锁,用来保证操作的一致性,比如用2个线程同时对一个变量累加1000,000次,得到的结果可能比2000,000少:

    package juc.test.cas;
    
    import org.junit.Test;
    
    import java.util.concurrent.CountDownLatch;
    
    public class NonAtomicTest {
    
        static long var = 0 ;
        final int totalThread = 2;
        final long timesEveryThread = 1000000;
        @Test
        public void testAtomicLong(){
    
            CountDownLatch cdl = new CountDownLatch(totalThread);  // thread count
    
            for (int j = 0; j < totalThread; j++) {
                new Thread(){
                    @Override
                    public void run() {
                        for (int i = 0; i < timesEveryThread; i++) {
                            var = var + 1;
                        }
                        cdl.countDown();
                    }
                }.start();
            }
    
            try {
                cdl.await();  // wait for all thread return
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(var);
        }
        
    }
    

    输出:

    1259956
    

    其中的原因有可能是因为他们读取的值一样,计算的结果也一样,而我们希望的结果是一个线程的操作是基于上次计算的结果,CAS可以保证,它的执行流程如图:

    值得一提的是,“比较(Compare)”和“交换(Swap)” 这两个操作需要合并为一个原子操作并加锁,也就是当有一个线程在进行cmpxchg时其他线程需要等待,防止出现2个线程同时compare发现都ok,然后都替换,比如两个线程都对i加1,i初始化为0,它们同时读取到i为0,并计算得到结果1,并且同时进行compare发现都是前值和现值都是0,很match,然后俩线程都写入1;加上一把锁,即使这俩线程同时读取到i为0,进行compare时必须有先后顺序,就可以保证操作的一致性了。

    Java的原子类AtomicInteger等是利用CAS算法实现的,例程的CAS版:

    package juc.test.cas;
    
    import org.junit.Test;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.atomic.AtomicLong;
    
    // See also ./hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp:93
    public class AtomicTest {
    
    
        final int totalThread = 2;
        final long timesEveryThread = 1000000;
        @Test
        public void testAtomicLong(){
            AtomicLong var = new AtomicLong() ;
            CountDownLatch cdl = new CountDownLatch(totalThread);
    
            for (int j = 0; j < totalThread; j++) {
                new Thread(){
                    @Override
                    public void run() {
                        for (int i = 0; i < timesEveryThread; i++) {
                            var.getAndIncrement();
                        }
                        cdl.countDown();
                    }
                }.start();
    
            }
    
            try {
                cdl.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(var.get());
        }
    
    }
    

    输出:

    2000000
    
  • 相关阅读:
    第一节:理解垃圾回收平台的基本工作原理
    回想笔记 瞎比比 域名注册 解析绑定ip 下载证书 设置证书 重定向http到https请求
    flask 设置https请求 访问flask服务器
    关于 服务器ip和域名进行一个绑定
    ubuntu 安装flask+nginx+gunicorn 待定
    使用flask-dropzone 上传图片文件
    flask 对于用户登录保持状态 flask_login
    flask 对于邮件url进行一个加密防止爆破
    flask 密码加密 视频资料
    flask 多线程邮件异步发送 视频资料
  • 原文地址:https://www.cnblogs.com/oaks/p/13418202.html
Copyright © 2011-2022 走看看