唐山网站建设设计网站统计分析工具
CAS
CAS(Compare-And-Swap,比较并交换),是一种原子操作,它的基本原理是:
- 比较:检查当前值是否等于预期值。
- 交换:如果相等,则修改为新值;否则,不做任何修改。
CAS 主要依赖 CPU 提供的原子指令(如 x86 的 cmpxchg 指令)
原子指令(Atomic Instructions)是 CPU 提供的一种特殊指令,保证操作不会被中断,可以一次性完成读取、计算和写入,从而确保并发环境下的线程安全。
原子变量(Atomic 类)
Java 提供 java.util.concurrent.atomic 包,实现了一系列基于 CAS 的原子变量,如:
- AtomicInteger:原子整型
- AtomicLong:原子长整型
- AtomicReference:原子引用类型
- AtomicStampedReference:解决 ABA 问题的版本控制原子引用
常见方法
- get() 获取当前值
- set(int newValue) 直接修改值(非原子)
- incrementAndGet() 自增 1
- decrementAndGet() 自减 1
- compareAndSet(int expect, int update) CAS 操作
示例
import java.util.concurrent.atomic.AtomicInteger;public class AtomicExample {private static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {System.out.println("Thread " + Thread.currentThread().getName() + " count: " + count.incrementAndGet());}).start();}}
}
这里 incrementAndGet() 是原子操作,保证多个线程不会同时修改 count 而发生数据竞争。
CAS存在问题
- ABA 问题:如果一个变量从 A → B → A,CAS 可能误认为它没有变化。
- 解决方案:使用AtomicStampedReference 记录版本号,避免误判。
- 自旋开销大:如果 CAS 频繁失败,线程会不断重试,消耗 CPU 资源。
- 只能更新单个变量:CAS 不能直接更新多个变量,需用 AtomicReference 组合多个变量。
AQS
AQS 通过状态变量 state(一个 volatile int 变量)和CLH 队列(FIFO 等待队列)来管理线程的同步访问。
AQS 是 Java 并发包的核心框架,用于构建锁和同步器(如 ReentrantLock、Semaphore)。
案例引入
public class Main {public static void main(String[] args) throws InterruptedException {int[] count = new int[]{1000};List<Thread> threads = new ArrayList<>();// Lock lock = new ReentrantLock();MyLock lock = new MyLock();for (int i = 0; i < 5; i++) {threads.add(new Thread(() -> {for (int i1 = 0; i1 < 5; i1++) {// lock.lock();count[0]--;}for (int i1 = 0; i1 < 5; i1++) {// lock.unlock();}}));}for (Thread thread : threads) {thread.start();}for (Thread thread : threads) {thread.join();}System.out.println(count[0]);}}
在主程序里,当把锁相关的代码注释后,就会造成并发安全的问题
那么我们能不能尝试造这样一把锁
锁的实现
public class MyLock {// 原子变量,指示是否拿到锁AtomicInteger state = new AtomicInteger(0);// 指示拥有锁的线程Thread owner = null;AtomicReference<Node> head = new AtomicReference<>(new Node());AtomicReference<Node> tail = new AtomicReference<>(head.get());void lock() {if (state.get() == 0) {if (state.compareAndSet(0, 1)) {// 拿到锁System.out.println(Thread.currentThread().getName() + "直接拿到锁");owner = Thread.currentThread();return;}} else {if (owner == Thread.currentThread()) {System.out.println(Thread.currentThread().getName() + " 拿到了重入锁,当前重入次数为" + state.incrementAndGet());return;}}// 没有拿到锁,把自己加入到阻塞链表Node current = new Node();current.thread = Thread.currentThread();while (true) {// 不断尝试获取当前链表尾结点,把自己加入尾结点后面Node currentTail = tail.get();if (tail.compareAndSet(currentTail, current)) {// 自己成为尾结点,修改链表结构System.out.println(Thread.currentThread().getName() + "加入到了链表尾");current.pre = currentTail;currentTail.next = current;break;}}while (true) {// 尝试自己自己唤醒自己一次(防止自己还没加入链表,拥有锁的线程已经结束了唤醒函数,这时就没有人再去唤醒了)if (current.pre == head.get() && state.compareAndSet(0, 1)) {owner = Thread.currentThread();head.set(current);current.pre.next = null;current.pre = null;System.out.println(Thread.currentThread().getName() + "被唤醒之后,拿到锁");return;}// 阻塞当前线程LockSupport.park();}}void unlock() {if (Thread.currentThread() != this.owner) {throw new IllegalStateException("当前线程并没有锁,不能解锁");}int i = state.get();if (i > 1) {state.set(i - 1);System.out.println(Thread.currentThread().getName() + "解锁了重入锁,重入锁剩余次数" + (i - 1));return;}if (i <= 0) {throw new IllegalStateException("重入锁解锁错误!");}Node headNode = head.get();Node next = headNode.next;state.set(0);if (next != null) {System.out.println(Thread.currentThread().getName() + "唤醒了" + next.thread.getName());// 唤醒下一个线程结点LockSupport.unpark(next.thread);}}class Node {Node pre;Node next;Thread thread;}}
参考:
https://blog.csdn.net/qq_35923846/article/details/140186945?ops_request_misc=%257B%2522request%255Fid%2522%253A%25227793918c79a5db9a8efbab96fc0d36d2%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=7793918c79a5db9a8efbab96fc0d36d2&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-2-140186945-null-null.142v101pc_search_result_base1&utm_term=aqs&spm=1018.2226.3001.4187
https://github.com/implement-study/lock_demo/tree/main/src/main/java/tech/insight
https://blog.csdn.net/u014745069/article/details/117875073?ops_request_misc=%257B%2522request%255Fid%2522%253A%25227793918c79a5db9a8efbab96fc0d36d2%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=7793918c79a5db9a8efbab96fc0d36d2&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-4-117875073-null-null.142v101pc_search_result_base1&utm_term=aqs&spm=1018.2226.3001.4187