解析JUC包底层源码实现
引言
上篇文章详细讲解了AQS底层架构,由等待队列和同步队列以及state信号量来实现,本篇文章将详细讲解JUC包是如何利用这些架构来实现各种组件的
ReentrantLock(可重入锁)
ReentrantLock 是一个独占锁,同一时刻只允许一个线程获取锁。它通过 AQS 的 state 变量来表示锁的重入次数,state 为 0 表示锁未被持有,大于 0 表示锁已被持有,且值表示持有线程的重入次数。
实现细节:
获取锁:ReentrantLock 有公平锁和非公平锁两种实现,它们都继承自 AQS 并重写了 tryAcquire 方法。以非公平锁为例,当线程尝试获取锁时,会先检查 state 是否为 0,如果是则尝试使用 CAS 操作将 state 设为 1,表示获取锁成功;如果 state 不为 0 且当前线程就是持有锁的线程,则将 state 加 1,表示重入。
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
释放锁:重写 tryRelease 方法,每次释放锁时将 state 减 1,当 state 减为 0 时,表示锁完全释放,此时会唤醒等待队列中的后继节点。
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
CountDownLatch(倒计时锁存器)
CountDownLatch 用于让一个或多个线程等待其他线程完成操作。它通过 AQS 的 state 变量作为计数器,初始值为需要等待的操作数量,每当一个操作完成时,调用 countDown() 方法将 state 减 1,当 state 减为 0 时,等待的线程会被唤醒。
实现细节:
初始化:在构造函数中设置 state 的初始值。
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
private static final class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count);
}
}
等待操作完成:调用 await() 方法,线程会尝试获取共享锁,只有当 state 为 0 时才能获取成功,否则线程会进入等待队列。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
操作完成通知:调用 countDown() 方法,会将 state 减 1,当 state 减为 0 时,会唤醒等待队列中的所有线程。
public void countDown() {
sync.releaseShared(1);
}
Semaphore(信号量)
Semaphore 用于控制同时访问某个资源的线程数量。它通过 AQS 的 state 变量表示可用的许可数量,线程在访问资源前需要先获取许可(acquire()),访问完成后释放许可(release())。
实现细节:
获取许可:调用 acquire() 方法,线程会尝试获取共享锁,通过减少 state 的值来表示获取许可。如果 state 小于请求的许可数量,则线程会进入等待队列。
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
释放许可:调用 release() 方法,会增加 state 的值,表示释放许可,同时会唤醒等待队列中的线程。
public void release() {
sync.releaseShared(1);
}