全路径名:java.util.concurrent.locks.ReentrantLock 类定义如下:
js
/**
* @since 1.5
*/
public class ReentrantLock implements Lock, java.io.Serializable {
...
}
ReentrantLock 类实现了 Lock 接口,JDK1.5 引入。
ReentrantLock 使用上分公平锁和非公平锁,两种锁机制。默认无参构造方法 ReentrantLock() 创建的是非公平锁。可以使用有参构造函数 ReentrantLock(boolean fair) 选择使用公平锁,还是非公平锁。具体实现是通过 ReentrantLock 的内部类 FairSync 和 NonfairSync 来实现的。FairSync 和 NonfairSync 是 ReentrantLock 类中抽象内部类 Sync 的子类。具体源码如下:
js
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 {...}
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public void lock() {
sync.lock();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
...
}
java.util.concurrent.locks.Lock 接口定义了5个方法。具体源码如下:
js
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
通过对 ReentrantLock 类 Lock 接口 lock() 方法的实现, 来看 ReentrantLock 是如何实现公平锁的。
先说方式,再看源码更好理解一点。如果要公平,那就要有先来后到。就像超市购物结账一样:
- 如果结账时,恰好没有人,那就直接结账。直接就拿到了锁。
- 如果结账时,已经有人了,那就排到队伍的后面,等到你的时候才可以结账。也就是拿到了锁。
ReentrantLock 内部类 FairSync 负责实现公平锁机制,FairSync 类继承了 Sync 类,Sync类 继承了 AbstractQueuedSynchronizer 类。下面是与 lock() 方法有个的源码:
js
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
js
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
...
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
...
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
...
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node)
&& parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
}
FairSync 的 lock() 方法调用 AbstractQueuedSynchronizer 类 acquire() 方法获取锁。AbstractQueuedSynchronizer 类 acquire() 方法中,先使用 FairSync 类的 tryAcquire() 方法实现没有人排队的场景。
- int c = getState(): 获取的是 AbstractQueuedSynchronizer 类的一个状态。c = 0 代表目前没有线程拿到这个锁
- !hasQueuedPredecessors(): 没有其他线程排队
- compareAndSetState(0, acquires):使用 CAS(Compare and Swap)CPU 硬件同步原语机制获取锁
- setExclusiveOwnerThread(current):如果成功拿到锁,将当前线程和锁绑定
- else if (current == getExclusiveOwnerThread()) 如果锁已经被当前线程绑定,状态 c 加 1。这块就体现了 ReentrantLock 可重入的概念。同一个线程未释放锁的情况下可以重复拿到锁,每次状态 c 加1。
AbstractQueuedSynchronizer 类 acquire() 方法中,如果没人排队的情况下,未能成功抢到锁。那就进入了排队的场景:
- for (;;) :无限循环
- if (p == head && tryAcquire(arg)):只有排队首的才有资格竞争锁。p 是获得锁的线程
- parkAndCheckInterrupt() 这个方法里实现的未获得锁的线程阻塞。这里不讨论。
看完 ReentrantLock 公平锁的实现,非公平锁的实现就简单了。非公平锁是通过 ReentrantLock 内部类 实现的,源码如下:
js
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);
}
}
abstract static class Sync extends AbstractQueuedSynchronizer {
...
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
...
}
从源码看一看出,不排队,直接调用 compareAndSetState(0, 1) 方法抢。这就是非公平锁。