《微服务实战》 第二十七章 CAS

系列文章目录

第二十八章 分布式锁框架-Redisson
第二十七章 CAS
第二十六章 Java锁的分类
第二十五章 Java多线程安全与锁
第二章 CountDownLatch和Semaphone的应用
第一章 Java线程池技术应用

在这里插入图片描述



前言

本章节介绍CAS概念、实现原理,并通过java代码实现CAS

1、CAS的概念

CAS的全称为:CompareAndSwap,直译为对比和交换。
CAS实际是普遍处理器都支持的一条指令,这条指令通过判断当前内存值V、旧的预期值A、即将更新的值B是否相等来对比并设置新值,从而实现变量的原子性。
Synchronized会线程阻塞称为悲观锁,CAS不会使线程阻塞称为乐观锁。悲观锁其他没有获取锁的线程是不会执行代码的,而乐观锁是可以使多个线程同时访问代码,可是会判断是否有更新决定是否重新执行。

2、CAS的实现原理

CAS的原理:通过三个参数,当前内存的变量值V、旧的预期值A、即将更新的值B。通过判断是V和A是否相等查看当前变量值是否被其他线程改变,如果相等则变量没有被其他线程更改,就把B值赋予V;如果不相等则做自旋操作。
举例:假设i的初始值为0,现两线程分别执行i++操作,看看CAS会如何执行:

1线程:A = 0,B = 1
2线程:A = 0,B = 1

此时两个线程的旧的期望值A、更新的B值都是一样的
假设1线程先执行,线程1从内存中拿到i的值V,此时V等于0,刚好和旧的期望值A相等,就把更新的值B赋值到内存i值V中。
2线程执行时,此时拿到内存的V值为1,和旧的预期值0不想等,则不做更新B的赋值操作,通过自旋把旧的预期值A=V,并再次确定CAS指令。
在这里插入图片描述

JDK提供的原子操作类就是基于CAS来实现原子性,比如:AtomicInteger、AtomicIntegerArray、AtomicDouble、AtomicBoolean等

3、单JVM内锁CAS实现

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/***
 * @title AtomicExample
 * @desctption CAS
 * @author Kelvin
 * @create 2023/6/14 17:08
 **/
public class AtomicExample {
    
    
    private static Map<String, Boolean> map = new HashMap<>();

    public static void main(String[] args) throws InterruptedException {
    
    
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //未加锁
        map.put("lock", true);
        for (int i = 0; i < 20; i++) {
    
    
            int finalI = i;
            executorService.submit(
                    () -> {
    
    
                        boolean isRotate = true;
                        while (isRotate) {
    
    
                            boolean vLock = map.get("lock");
                            if( vLock ) {
    
    
                                boolean aLock = map.get("lock");
                                if( vLock == aLock ) {
    
    
                                    //执行业务逻辑
                                    //加锁
                                    map.put("lock", false);
                                    System.out.println( "执行业务逻辑, i: " + finalI);
                                    try {
    
    
                                        Thread.sleep(2000);
                                    } catch (InterruptedException e) {
    
    
                                        throw new RuntimeException(e);
                                    }
                                    isRotate = false;
                                    //释放锁
                                    map.put("lock", true);
                                } else {
    
    
                                    System.out.println("自旋,重新获取锁!");
                                    continue;
                                }
                            }
                        }
                    }
            );
        }

        Thread.sleep(20 * 1000);
        System.out.println("end");
        executorService.shutdown();
        
    }
}

3.1、效果

执行业务逻辑, i: 1
执行业务逻辑, i: 5
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 4
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 10
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 9
执行业务逻辑, i: 2
自旋,重新获取锁!
执行业务逻辑, i: 3
自旋,重新获取锁!
执行业务逻辑, i: 0
执行业务逻辑, i: 12
执行业务逻辑, i: 11
执行业务逻辑, i: 8
执行业务逻辑, i: 6
执行业务逻辑, i: 7
执行业务逻辑, i: 14
自旋,重新获取锁!
执行业务逻辑, i: 15
执行业务逻辑, i: 16
执行业务逻辑, i: 18
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 17
执行业务逻辑, i: 19
执行业务逻辑, i: 13
end

猜你喜欢

转载自blog.csdn.net/s445320/article/details/130951405