系列文章目录
第二十八章 分布式锁框架-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