一、概述
ReentrantLock是一个可重入锁。具有公平性和非公平性两种模式。
可重入:如果当前线程已经获取到锁了,在再次获取的时候可以对共享资源重复加锁,不需要重新排队即可获取到。
公平锁:线程获取锁必须按照FIFO的模式排队获取,先到先得。
非公平锁:允许队列后面的线程先获取锁。
二、ReentrantLock的相关属性与构造方法
Sync sync:ReentrantLock中仅有的一个属性
默认非公平锁的构造方法
public ReentrantLock() {
sync = new NonfairSync();
}
可以设置为公平锁的构造方法:
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
从上面两个方法可以看到在ReentrantLock中是存在NonfairSync、FairSync、Sync这三个对象的。这三个对象是怎么一回事?接着往下看ReentrantLock的源码:
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
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;
}
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;
}
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
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;
}
}
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
}
从上述代码中可见ReentrantLock是存在三个内部类的,也就是说上面提到的三个对象都是ReentrantLock的内部类。其中Sync继承了AbstractQueuedSynchronizer类(AQS),NonfairSync和FairSync都继承了Sync的。
所以公平锁是让FairSync构建sync对象,非公平锁是让NonfairSync构建sync对象。线程在AbstractQueuedSynchronizer中是保存在 Node 对象中的。
三、可重入的实现
先看代码
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 获取贡献资源的上锁次数
int c = getState();
// 如果没有被上锁
if (c == 0) {
// 通过CAS获取同步状态,获取锁
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;
}
上述代码中的第二个条件分支,如果当前执行线程等于获取到锁的线程,则证明是同一条线程,则获取到锁的次数相加,就是同一条线程再次获得了锁,实现了重入。锁被多次获取也就会被多次释放,只有释放到state等于0时,才能完全释放锁。
四、锁的获取
公平锁的获取:
公平锁通过当前线程是否是队列中的head和当前线程是否是已经获取到锁的线程作为依据 来判断当前线程是否能够获取到锁。如果符合条件,则将AQS中的独享线程设置为当前线程。否则假如等待队列。
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 获取状态
int c = getState();
// 未上锁
if (c == 0) {
// 判断当前线程是否是head,如果是,通过 CAS 获取锁
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;
}
否则加入等待队列,当前线程状态设置为阻塞
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;
}
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
非公平锁的获取:
和公平锁的获取差不多
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;
}
在state为0时,非公平锁比公平锁少了一个获取到锁的条件,不要求线程是队列中的head。
五、锁的释放
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;
}
参考博客:https://juejin.im/post/5aeb0a8b518825673a2066f0
参考博客:https://www.cnblogs.com/iou123lg/p/9535710.html
参考博客:https://tech.meituan.com/2019/12/05/aqs-theory-and-apply.html
建议去看上面的三个参考博客。