AQS的原理(1)

AQS


AQS中同步状态

其中state表示同步状态,为32位整数,用来表示锁的数量。

AQS主体流程

AQS中提供了获取和释放锁有两种模式:独占式和共享式。

1.  独占模式:

1)  acquire:以独占的模式获取对象,忽略中断。

2)  acquireInterruptibly:以独占模式获取对象,如果中断则停止。

3)  release:以独占模式释放对象。

2.  共享模式:

1)  acquireShared:以共享模式获取对象,忽略中断。

2)  acquireSharedInterruptibly:以共享模式获取对象,如果被中断则中止。

3)  releaseShared:以共享模式释放对象。

PS:独占模式可以视为共享模式的特例,共享数量为1.

3.  主体流程:

1)  线程通过acquireSharedInterruptibly获取锁,操作完成后。

2)  通过releaseShared来释放锁。


3)  程序获取锁失败后(通过调用acquireSharedInterruptibly),将进入等待队列,然后进入阻塞状态(经过一些判断之后)

4)  当另一个线程释放锁后(通过调用releaseShared),将执行唤醒阻塞线程的操作;被唤醒的线程将把自己移出等待队列,并执行一些其它操作

等待队列

AQS中使用FIFO的队列来管理等待获取锁的线程。

1.        主要流程:

1)        入队列:线程获取锁失败后,调用doAcquireSharedInterruptibly方法。

a)        创建一个新的结点。

b)        将结点添加到等待队列队尾。

c)        将线程阻塞。

2)        唤醒:其它线程释放锁资源,调用releaseShared中doReleaseShared方法。

a)        获取队列中的第一个结点。

b)        将节点对应线程唤醒。

c)        该线程将尝试获取锁,成功后将自己移除等待队列。

d)        判断是否仍然有空闲锁,若有则继续唤醒下一个结点。

2.        每次只会唤醒第一个节点,如果同时释放多个锁,后续的节点将由前面被唤醒的节点来唤醒,尽量减少数据竞争。

阻塞机制

1.        作用:

1)        阻塞新添加到等待队列中的线程。

2)        唤醒等待队列中对头的等待线程。

2.        实现:使用Unsafe的park和unpark实现的


Condition

1.        作用:Condition实例始终被绑定到一个锁(Lock)上,Lock替代了Java的synchronized方法,而Condition则替代了Object的监视器方法,包括wait、notify和notifyAll。即起到线程间通信的作用。提供awaitsignalsignalAll方法。

2.        使用:


3.        主要方法:

1)        Await():阻塞当前前程,直到有信号到来唤醒它。

a)        可能被唤醒的时机:

Ø  其他某线程调用了此Condition的signal()方法

Ø  其他某线程调用此Condition的SignalAll()方法

Ø  其他某线程中断当前线程

Ø  超过指定等待时间

Ø  发生“虚假唤醒”

否则一直处于等待状态

b)        阻塞过程:

1.      如果当前线程被中断,则抛出中断异常;

2.      入队:将当前线程放置到Condition的等待队列中;

3.      释放锁资源:释放当前线程的锁,并且保存锁定状态;

4.        循环检测:在收到信号、中断或超时前,一直阻塞;

5.        放行:使用保存的锁定状态重新获取锁;

6.        如果步骤4的阻塞过程中发生中断,则抛出中断异常

PS:将阻塞放入到循环中---à防止“虚假唤醒”

         保存锁定状态---------à使用排他模式

2)        Signal():唤醒一个线程。即将当前Condition的等待队列中的第一个结点移动到拥有锁的等待队列中等待执行。

3)        signalAll():将当前Condition的等待队列中的所有结点移到拥有锁的等待队列中。等待执行。

### Java AQS (AbstractQueuedSynchronizer) 原理详解 #### AQS概述 AQS 是一个用于构建锁和其他同步组件的基础框架。此框架的核心思想在于使用单个 `volatile` 整形变量 `state` 来表示同步状态,并通过内置的 FIFO 队列来完成获取和释放同步状态时的排队工作[^3]。 #### 同步状态管理 AQS 使用一个名为 `state` 的私有成员变量来保存同步状态,这个变量被声明为 `volatile` 类型以确保多线程环境下的可见性和有序性。对于不同的同步器而言,`state` 可能代表的意义有所不同。例如,在 `ReentrantLock` 中,`state` 表示的是持有锁的数量;而在 `Semaphore` 中,则可能表示剩余许可数[^5]。 #### 线程竞争处理 当多个线程尝试访问受保护资源时,如果当前线程无法立即获得所需的同步状态(比如因为已经被占用),那么该线程将会加入到由 AQS 维护的一个先进先出(FIFO)队列之中等待。每当某个线程成功释放了其持有的同步状态之后,处于队首位置的那个等待线程便有机会重新尝试获取同步状态并继续执行下去。 #### 自定义同步逻辑实现 为了适应各种各样的需求场景,开发者可以通过继承自 `AbstractQueuedSynchronizer` 并覆盖其中的关键方法来自定义特定类型的同步行为。具体来说: - 对于独占模式下使用的同步器(如 `ReentrantLock`),通常会重载 `tryAcquire(int arg)` 和 `tryRelease(int arg)` 方法; - 而共享模式则适用于允许多个线程同时拥有相同权限的情况(像信号量),此时应着重关注 `tryAcquireShared(int arg)` 和 `tryReleaseShared(int arg)` 这两个函数的编写[^2]。 ```java // 定义一个新的同步器类 public class MySync extends AbstractQueuedSynchronizer { protected boolean tryAcquire(int acquires) { /* ... */ } protected boolean tryRelease(int releases) { /* ... */ } // 如果是共享模式还需要实现如下方法 protected int tryAcquireShared(int acquires) { /* ... */ } protected boolean tryReleaseShared(int releases) { /* ... */ } } ``` #### CAS操作保障原子性 由于存在并发修改的可能性,所以在更改 `state` 的时候必须采取措施防止竞态条件的发生。为此,AQS 利用了硬件层面提供的比较交换指令(CAS Compare And Swap)来进行无锁编程,从而保证了对 `state` 更新过程的安全可靠[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值