AQS
简介
AQS(AbstractQueuedSynchronizer)是Java中用于实现同步器的抽象基类。它提供了一种灵活的方式来创建自定义的同步器,如锁、信号量等。AQS的底层包含了一些重要的成员变量,其中最重要的是state,用于表示同步状态,以及一个双向链表,用于维护等待线程。
互斥锁: 在互斥锁中,state通常为0表示锁是可用的,为1表示锁被占用。当线程获取锁时,会尝试将state从0修改为1,如果成功,线程获得了锁
内部结构
CAS
CAS 操作通常包含以下三个参数:
内存位置(通常是一个变量的引用)。
预期值(当前内存位置的值)。
新值(用来替换内存位置的值)。
CAS 操作执行的逻辑是:
比较内存位置的值与预期值。
如果相等,将内存位置的值更新为新值。
如果不相等,CAS 操作不执行更新,并返回失败。
CAS与ABA问题
ABA问题是指在多线程环境下,如果一个值从A变为B,然后再变回A,CAS操作会错误地认为它的值从未改变过。这可能导致意外的结果,特别是在一些需要关注数据的连续性的情况下。
自定义一个自己的AQS
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class CustomLock {
// AQS成员变量
private final Sync sync = new Sync();
// 自定义同步器继承AQS
static class Sync extends AbstractQueuedSynchronizer {
// 在AQS中,最重要的成员变量之一,表示同步状态
// int state;
// 构造函数
Sync() {
setState(0); // 初始状态
}
@Override
protected boolean tryAcquire(int acquires) {
// 重写tryAcquire方法以获取锁
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
}
return false;
}
@Override
protected boolean tryRelease(int releases) {
// 重写tryRelease方法以释放锁
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
int c = getState() - releases;
if (c == 0) {
setExclusiveOwnerThread(null);
}
setState(c);
return true;
}
// 其他自定义方法可以根据需要添加
}
public void lock() {
sync.acquire(1);
}
public void unlock() {
sync.release(1);
}
}
AQS核心
假设多线程环境,第一个持有锁,其他的CAS操作失败阻塞住,以此放到AQS同步队列中
线程0释放锁,线程1被唤醒获取锁
队头元素出队(就是null结点)
AQS源码