1. ReentrantLock
ReentrantLock是可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞而被放入该锁的AQS阻塞队列里面
@Test
public void reentrantLock() {
ReentrantLock fairLock = new ReentrantLock(true);
ReentrantLock nonFairLock = new ReentrantLock();
ReentrantLock nonFairLock2 = new ReentrantLock(false);
}
特性:
- 可重入
- 可中断
- 可设置超时时间
- 可以设置为公平锁(先进先出)
- 支持多个条件变量
- synchronized 只有一个 waitSet
- reentrantLock 可以有多个 waitSet
2. 实战
2.1 synchronized 与 reentrantLock
- synchronized 是在关键字级别保护临界区
- reentrantLock 是在对象级别保护临界区
try {
// 临界区
} final {
reentrantLock.unlock();
}
3. 源码分析
- ReentrantLock 实现 Lock 接口,有 3 个内部类:Sync, NonfairSync, FairSync
- Sync 类继承自抽象类 AbstractQueuedSynchronizer(AQS),它的子类 NonfairSync 和 FairSync 分别实现了获取锁的非公平与公平策略
/**
* 看注释...
* A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it
*/
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
}
static final class NonfairSync extends Sync {
}
static final class FairSync extends Sync {
}
}
3.1 成员变量 sync
private final Sync sync;
变量 sync 用来指向 Sync 子类,也就是FairSync或者NonfairSync,多态的父类引用指向子类,具体Sycn指向哪个子类,看构造方法
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
3.2 内部类 Sync
Sync 重写的方法 tryRelease, tryAcquire(子类重写),ReentrantLock实现的是AQS的独占模式,也就是独占锁,这个锁是悲观锁
3.3 lock()
ReentrantLock 的 lock() 委托给 sync 类
public class ReentrantLock implements Lock, java.io.Serializable {
public void lock() {
sync.lock();
}
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
}
static final class NonfairSync extends Sync {
// 非公平锁实现
final void lock() {
// boolean compareAndSetState(int expect, int update)
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 调用 AQS 的 acquire()
acquire(1);
}
}
static final class FairSync extends Sync {
// 公平锁实现
final void lock() {
acquire(1);
}
}
}
分析非公平锁
lock() 调用 CAS方法设置state的值
setExclusiveOwnerThread设置该锁持有者是当前线程
AQS 的 acquire()
public final void acquire(int arg) {
// ReentrantLock 重写 tryAcquire()
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), arg))
selfInterrupt();
}
扩展:
AQS 的 state状态值表示线程获取该锁的可重入次数,
state 默认为0,表示当前锁没有被任何线程持有
当一个线程第一次获取该锁时会尝试使用CAS设置state的值为1,如果CAS成功则当前线程获取了该锁,然后记录该锁的持有者为当前线程。在该线程没有释放锁的情况下第二次获取该锁后,状态值被设置为2,这就是可重入次数。在该线程释放该锁时,会尝试使用CAS让状态值减1,如果减1后状态值为0,则当前线程释放该锁