
本文共 3238 字,大约阅读时间需要 10 分钟。
AbstractQueuedSynchronizer(简称AQS)是Java并发编程中非常重要的同步机制,它为复杂的多线程应用提供了基础的后勤支持。作为其他同步类(如ReentrantLock)的基石,AQS通过两种队列——同步队列和条件队列——来协调线程的进入和中断过程。
AQS 的核心逻辑
AQS 的主要目标是支持线程之间的竞争性和协调性。当一个线程试图获取某个锁时,如果锁被其他线程占有,请求线程就会进入AQS的条件等待机制。这一机制通过条件队列(Condition Queue)来管理线程的中断状态。
条件队列:线程的等待室
条件队列(Condition Queue)类似于一个快乐的面板,上面记录了线程因为某些条件而被暂停的状态。在AQS中,条件队列主要有以下功能:
- 接收需要等待的线程
- 醉酒请等等...
当线程因为某种条件而无法继续执行时,它会将自己从同步队列中移出,并进入条件队列等待。这时,线程进入一种潜在状态,等待某些特定条件被满足,例如另一个线程释放锁并完成某项工作。
条件队列中的每个记录都与一个线程相关,线程在接收到信号(通过signal方法调用)后会被唤醒并重新加入同步队列等待锁。
signal 方法: 唤醒线程
signal方法是AQS中非常重要的一招,它负责唤醒条件队列中的线程。具体来说,signal方法执行以下操作:
这意味着,只要一个线程进入条件队列,它都会在signal方法被唤醒。而signalAll方法则会继续处理整个条件队列中的所有线程,将其全部唤醒。
await 方法: 线程的等待状态
await方法是线程在遇到阻塞时使用的核心功能。当线程发现自己无法继续获取锁时,就会调用await方法,进入条件队列等待。具体来说,await方法的实现分为以下几个步骤:
这一过程确保了线程在离开锁后不会立即干扰其他线程,从而保持了锁的互斥性。
条件队列的处理逻辑
在详细解读源码之前,我们需要理解条件队列的处理逻辑。首先要了解的是,如何将条件队列中的线程唤醒,以及哪些情况下会触发唤醒。通常,唤醒的条件包括:
通过这三种情况,AQS确保了线程等待的效率和准确性。
源码分析
Response-sensitive Condition await()
public final void await() throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } Node node = addConditionWaiter(); int savedState = fullyRelease(node); boolean interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) { break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) { interruptMode = REINTERRUPT; } if (node.nextWaiter != null) { unlinkCancelledWaiters(); } if (interruptMode != 0) { reportInterruptAfterWait(interruptMode); } } // ... 后续操作 }
No-interruptible Condition await()
public final void awaitUninterruptibly() { Node node = addConditionWaiter(); int savedState = fullyRelease(node); while (!isOnSyncQueue(node)) { LockSupport.park(this); if (Thread.interrupted()) { boolean interrupted = true; } } if (acquireQueued(node, savedState) || interrupted) { selfInterrupt(); } }
Timed Condition await()
public final long awaitNanos(long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } Node node = addConditionWaiter(); int savedState = fullyRelease(node); long lastTime = System.nanoTime(); long nanosRemaining = nanosTimeout; while (!isOnSyncQueue(node)) { if (nanosRemaining <= 0) { transferAfterCancelledWait(node); break; } LockSupport.parkNanos(this, nanosRemaining); nanosRemaining -= System.nanoTime() - lastTime; lastTime = System.nanoTime(); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) { break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) { interruptMode = REINTERRUPT; } if (node.nextWaiter != null) { unlinkCancelledWaiters(); } if (interruptMode != 0) { reportInterruptAfterWait(interruptMode); } } return nanosRemaining - (System.nanoTime() - lastTime); }
总结
通过以上分析可以看出,AbstractQueuedSynchronizer为Java 的 Locking机制提供了一种灵活且高效的条件等待方式。它通过同步队列和条件队列,协调多线程环境中的资源竞争和等待状态,这使得复杂的同步操作更加高效和可靠。
AQS 是现代Java 式的基石,它不仅用于ReentrantLock,还为其他同步机制如Semaphore、ConcurrentQueue等提供了强大的后勤支持。如果你对这个话题有进一步的兴趣,可以深入探索它的具体实现细节。
发表评论
最新留言
关于作者
