ReentrantLock可重入锁的实现原理
首先先介绍Lock接口,然后通过分析ReentrantLock的lock方法和unlock方法,来解释ReentrantLock的内部原理.
1. Lock接口
Lock接口,是对控制并发的工具的抽象。它比使用synchronized关键词更灵活,并且能够支持条件变量。
- 它是一种控制并发的工具,一般来说,它控制对某种共享资源的独占。也就是说,同一时间内只有一个线程可以获取这个锁并占用资源。其他线程想要获取锁,必须等待这个线程释放锁。在Java实现中的ReentrantLock就是这样的锁。
- 另外一种锁,它可以允许多个线程读取资源,但是只能允许一个线程写入资源,ReadWriteLock就是这样一种特殊的锁,简称读写锁。
lock接口常见的几个方法:
- lock():获取锁,如果锁无法获取,那么当前的线程就变为不可被调度,直到锁被获取到,当前线程不可被中断
- unlock 释放当前线程占用的锁
- lockInterruptibly :获取锁,除非当前线程被中断。
- tryLock:如果调用的时候能够获取锁,那么就获取锁并且返回true,如果当前的锁无法获取到,那么这个方法会立刻返回false
- newCondition:返回一个与当前的锁关联的条件变量。在使用这个条件变量之前,当前线程必须占用锁。调用Condition的await方法,会在等待之前原子地释放锁,并在等待被唤醒后原子的获取锁
2. 公平锁和非公平锁的实现
2.1 公平锁
公平锁对应的逻辑是 ReentrantLock 内部静态类 FairSync
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
// AbstractQueuedSynchronizer.acquire(int arg)
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 1. 和非公平锁相比,这里多了一个判断:是否有线程在等待
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;<