AQS原理详解

一、核心组成部分

(一)同步状态(state)

AQS使用一个volatile修饰的int类型变量state表示同步状态 ,不同的同步器对state的含义有不同定义。以ReentrantLock为例,state表示锁被同一个线程重复获取的次数,0代表未锁定,大于0表示已锁定,数值为获取次数;在Semaphore中,state表示剩余的许可数量。对state的操作主要通过getState()setState()compareAndSetState()这三个方法,compareAndSetState()利用CAS操作保证了state在多线程环境下修改的原子性,确保了对同步状态的安全操作。

(二)FIFO等待队列

AQS维护了一个基于双向链表实现的FIFO(先进先出)等待队列,用于管理等待获取资源的线程。队列中的每个节点(Node)代表一个线程,节点包含了线程的引用、等待状态(waitStatus)等信息。等待状态常见的值有:

  • SIGNAL(值为 -1):表示后续节点需要被唤醒。
  • CANCELLED(值为1):表示线程已取消等待,可能因为等待超时或被中断。
  • CONDITION(值为 -2):表示线程在条件队列中等待。
  • PROPAGATE(值为 -3):在共享模式下,用于表示下一次共享式同步状态获取将会无条件传播下去。
    当线程获取资源失败时,会被包装成一个Node节点加入到等待队列的尾部。

二、资源获取与释放机制

(一)资源获取

线程通过调用AQS的acquire(int arg)方法尝试获取资源。该方法首先会调用tryAcquire(arg)方法(此方法由具体的子类实现 )尝试获取资源。如果tryAcquire返回true,说明获取资源成功;如果返回false,就会调用addWaiter(Node.EXCLUSIVE)将当前线程加入等待队列,然后通过acquireQueued方法使线程在队列中不断尝试获取锁,直到成功或被中断。在acquireQueued方法中,线程会先判断当前节点的前驱节点是否为head节点(队列头节点不关联具体线程,仅作为标记 ),如果是则再次尝试获取锁;如果不是或者获取锁失败,会根据前驱节点的waitStatus值判断是否需要将当前线程挂起(通过LockSupport.park()操作 )。

(二)资源释放

持有资源的线程调用AQS的release(int arg)方法释放资源。该方法会先调用tryRelease(arg)方法(同样由子类实现)尝试释放资源。如果tryRelease返回true,代表资源已成功释放,此时会检查等待队列的头节点,如果头节点存在且其waitStatus不为0,就调用unparkSuccessor方法唤醒头节点的后继节点(即等待队列中的下一个线程),被唤醒的线程会再次尝试获取资源。

三、独占模式与共享模式

(一)独占模式(Exclusive Mode)

在独占模式下,同一时间只有一个线程能获取同步状态(例如锁),其他线程必须等待。以ReentrantLock为例,当线程获取同步状态(锁)时,如果成功则进入临界区执行代码;如果失败,线程进入同步队列等待。当持有锁的线程释放锁时,队列中的下一个线程被唤醒并尝试获取锁。独占模式适用于所有只能有一个线程访问临界区的场景,保证了数据的一致性和操作的原子性。

(二)共享模式(Shared Mode)

在共享模式下,多个线程可以同时获取同步状态(如共享资源),允许多个线程并发执行。例如Semaphore(信号量),它的acquire()方法用于争抢资源,release()方法用于释放资源。当多个线程试图获取同步状态时,如果资源充足(state大于0 ),多个线程可以同时获得访问权限;如果资源不足,部分线程进入同步队列等待。当资源释放时,队列中的等待线程可以被唤醒并继续尝试获取资源。共享模式适用于需要允许多个线程同时访问共享资源的场景,提高了资源的利用率和并发性能。

四、条件变量(Condition)

AQS通过ConditionObject类提供了条件等待/通知机制,类似于Objectwait()/notify()机制,但功能更强大。一个AQS对象可以创建多个Condition实例,每个Condition实例都维护了一个等待队列。线程可以调用Conditionawait()方法将自己加入到对应的等待队列中并释放持有的锁,进入等待状态;当其他线程调用Conditionsignal()方法时,会唤醒等待队列中的一个线程,被唤醒的线程会尝试重新获取锁;调用signalAll()方法则会唤醒等待队列中的所有线程。

五、AQS在实际同步器中的应用

(一)ReentrantLock

ReentrantLock是基于AQS实现的可重入独占锁。它内部有一个抽象类Sync继承自AQS,Sync有两个具体子类FairSync(公平锁)和NonfairSync(非公平锁)。公平锁在获取锁时会检查等待队列中是否有其他线程在排队,按照线程等待的先后顺序分配锁;非公平锁获取锁时先通过CAS尝试获取,不考虑等待队列中的线程,可能会使新线程“插队”获取锁。在加锁时,线程调用lock()方法,实际是调用AQS的acquire(1)方法;解锁时,调用unlock()方法,实际是调用AQS的release(1)方法。

(二)Semaphore

Semaphore(信号量)基于AQS实现了共享锁机制,用于控制同时访问特定资源的线程数量。通过acquire()方法获取许可(state减1 ),如果state小于0,线程进入等待队列;通过release()方法释放许可(state加1 ),并唤醒等待队列中的线程。

(三)CountDownLatch

CountDownLatch(倒计时锁)也是基于AQS实现的同步工具。state表示剩余的操作次数,线程调用await()方法时,如果state不为0,则进入等待队列;其他线程调用countDown()方法会使state减1,当state变为0时,会唤醒所有等待的线程。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值