AQS同步工具类对比

工具类工具类作用工具类加锁方法工具类释放锁方法Sync覆盖的方法Sync非覆盖的重要方法state的作用锁类型锁维护
Semaphore控制同时访问某个特定资源的操作数量acquire:每次请求一个许可都会导致计数器减少1,,一旦达到了0,新的许可请求线程将被挂起release:每调用 添加一个许可,释放一个正在阻塞的获取者tryAcquireShared
tryReleaseShared
 
表示初始化的许可数共享锁每一次请求acquire()一个许可都会导致计数器减少1,同样每次释放一个许可release()都会导致计数器增加1,一旦达到了0,新的许可请求线程将被挂起。
CountDownLatch把一组线程全部关在外面,在某个状态时候放开。一种同步机制来保证一个或多个线程等待其他线程完成。await:在计数器不为0时候阻塞调用线程,为0时候立即返回countDown :计数递减tryAcquireShared 
tryReleaseShared
 
维护一个计数器共享锁初始化一个计数,每次调用countDown方法计数递减,在计数递减到0之前,调用await的线程都会阻塞
ReentrantLock标准的互斥操作,也就是一次只能有一个线程持有锁lock:如果没有线程使用则立即返回,并设置state为1;如果当前线程已经占有锁,则state加1;如果其他线程占有锁,则当前线程不可用,等待 tryLock:如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 falseunlock:尝试释放锁,如果当前线程占有锁则count减一,如果count为0则释放锁。如果占有线程不是当前线程,则抛异常tryAcquire 
tryRelease
nonfair
TryAcquire
state表示获得锁的线程对锁的重入次数。排他锁。获取锁时,如果没有线程使用则立即返回,并设置state为1;如果当前线程已经占有锁,则state加1;如果其他线程占有锁,则当前线程不可用。释放锁时,在该方法中主要作用是state状态位减少release个,表示释放锁,如果更新后的state为0,表示当前线程释放锁,如果不为0,表示持有锁的当前线程重入数减少
ReentrantReadWriteLock读写锁。允许多个读线程同时持有锁,但是只有一个写线程可以持有锁。写线程获取写入锁后可以再次获取读取锁,但是读线程获取读取锁后却不能获取写入锁ReadLock#lock :获取读锁 ReadLock#tryLock:尝试当前没有其他线程当前持有写锁时获取读锁 WriteLock#lock:获取写锁 WriteLock#tryLock:尝试当前没有其他线程持有写锁时,呼气写锁。ReadLock#unlock:释放读锁 WriteLock#unlock:释放写锁acquireShared 
releaseShared
tryAcquire 
tryRelease
tryReadLock
tryWriteLock
高16位表示共享锁的数量,低16位表示独占锁的重入次数读锁:共享 写锁:排他对于共享锁,state是计数器的概念。一个共享锁就相对于一次计数器操作,一次获取共享锁相当于计数器加1,释放一个共享锁就相当于计数器减1;排他锁维护类似于可重入锁。
FutureTask封装一个执行任务交给其他线程去执行,开始执行后可以被取消,可以查看执行结果,如果执行结果未完成则阻塞。V get()run() set(V) cancel(boolean)tryAcquireShared 
tryReleaseShared
innerGet innerRun() innerSet innerIsCancelledstate状态位来存储执行状态RUNNING、RUN、CANCELLED共享锁获取执行结果的线程(可以有多个)一直阻塞,直到执行任务的线程执行完毕,或者执行任务被取消。

<think>嗯,用户之前问过JUC并发工具包,现在接着问AQS的实现原理,看来他们可能在学习Java并发编程,想要深入理解JUC的核心组件。AQS作为JUC中锁和同步器的基础框架,确实是一个关键点。用户可能是开发者,需要了解底层机制来优化代码或解决并发问题。 首先,我需要回忆AQS的基本结构,比如它如何通过一个int类型的state变量来表示资源状态,以及CLH队列的管理。用户可能想知道AQS是如何实现线程的阻塞和唤醒的,所以得解释Node节点和CAS操作的作用。同时,他们可能对独占模式和共享模式的区别感兴趣,需要分别说明。 然后,模板方法模式在AQS中的应用也很重要,用户可能想知道如何通过重写tryAcquire等方法来实现自定义同步器。比如ReentrantLock和Semaphore的不同实现方式,这时候举例子会帮助理解。 另外,用户可能对AQS中的公平和非公平模式有疑问,需要解释两者的区别,比如非公平模式如何减少线程切换开销。还有,如何处理中断和超时,这也是实际开发中常见的问题,得提到相关的方法如acquireInterruptibly。 在思考过程中,要确保覆盖AQS的核心设计,比如CLH变体队列、CAS操作、资源状态管理,以及具体的应用场景。同时,结合用户之前的JUC问题,可能需要将AQS与其他并发工具(如CountDownLatch、ReentrantLock)联系起来,说明它们如何依赖AQS实现。 最后,用户可能希望了解学习AQS的建议,比如阅读源码或调试示例,这部分需要给出实用的建议,帮助他们进一步掌握。要避免过于技术化的术语,用易懂的语言解释清楚原理和实现细节,确保回答结构清晰,逐步深入,满足用户的需求。</think>AQS(AbstractQueuedSynchronizer)是Java并发包的核心框架,JUC中大多数同步工具(如ReentrantLock、CountDownLatch等)都基于它实现。其核心原理可分为以下关键部分: --- ### **一、核心数据结构** 1. **state变量(volatile int)** - 表示同步状态的核心字段 - 不同工具类的语义不同: $$ \begin{cases} \text{ReentrantLock: 锁重入次数} \\ \text{Semaphore: 剩余许可数} \\ \text{CountDownLatch: 剩余计数器} \end{cases} $$ 2. **CLH队列变体** - 使用双向链表实现的等待队列(FIFO) - 每个节点对应等待线程(Node内部类) --- ### **二、关键工作机制** #### 1. **资源访问控制** - **独占模式**(Exclusive) ```java // 如ReentrantLock acquire(int arg) → tryAcquire(arg) → addWaiter() → acquireQueued() ``` - **共享模式**(Shared) ```java // 如Semaphore acquireShared(int arg) → tryAcquireShared(arg) → doAcquireShared() ``` #### 2. **线程阻塞/唤醒** - 通过`LockSupport.park()`/`unpark()`实现 - 当线程获取资源失败时,构建Node加入队列并阻塞 - 前驱节点释放资源时触发唤醒 --- ### **三、核心方法实现** #### 1. **获取资源(以独占模式为例)** ```java public final void acquire(int arg) { if (!tryAcquire(arg) && // 尝试直接获取(需子类实现) acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 加入队列并等待 selfInterrupt(); } ``` #### 2. **释放资源** ```java public final boolean release(int arg) { if (tryRelease(arg)) { // 尝试释放(需子类实现) Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); // 唤醒后继节点 return true; } return false; } ``` --- ### **四、关键技术实现** #### 1. **CAS操作** - 通过Unsafe类实现队列节点操作: $$ \text{compareAndSetHead(Node update)} $$ $$ \text{compareAndSetTail(Node expect, Node update)} $$ #### 2. **队列同步策略** - **自旋检测**:队列中线程不断检查前驱节点状态 - **取消机制**:超时/中断时移除无效节点 - **头节点唤醒**:仅头节点有资格尝试获取资源 --- ### **五、设计模式** 1. **模板方法模式** - 需要子类实现的关键方法: $$ \begin{cases} \text{tryAcquire(int)} \\ \text{tryRelease(int)} \\ \text{tryAcquireShared(int)} \\ \text{tryReleaseShared(int)} \end{cases} $$ 2. **公平/非公平策略** - 公平锁:严格按照队列顺序获取 - 非公平锁:允许插队(减少上下文切换) --- ### **六、典型实现对比** | 同步器 | 使用模式 | state语义 | 关键方法实现 | |----------------|-----------|------------------|---------------------------| | ReentrantLock | 独占 | 重入次数 | tryAcquire()检查当前线程是否持有 | | Semaphore | 共享 | 可用许可数 | tryAcquireShared()扣减许可数 | | CountDownLatch | 共享 | 剩余计数器 | tryReleaseShared()递减计数 | --- ### **七、源码级关键细节** 1. **节点状态(waitStatus)** ```java static final int CANCELLED = 1; // 线程已取消 static final int SIGNAL = -1; // 需要唤醒后继节点 static final int CONDITION = -2; // 在条件队列中等待 ``` 2. **资源获取的两种方式** - **不可中断模式**:acquire() - **可中断模式**:acquireInterruptibly() --- ### **八、最佳实践建议** 1. 优先使用现有的JUC工具类,避免直接继承AQS 2. 实现自定义同步器时: - 准确维护state状态 - 正确处理线程中断 - 合理选择公平/非公平策略 3. 使用`Condition`对象时注意与锁的绑定关系 --- ### **学习建议** 1. 从`ReentrantLock`源码入手理解独占模式 2. 使用IDEA调试线程排队/唤醒过程 3. 通过`AbstractQueuedSynchronizer`的Javadoc理解设计思想 AQS通过精妙的队列管理和状态控制,实现了高性能的同步机制,是理解Java并发编程的核心基石。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值