ReentrantLock原理 - 969251639/study GitHub Wiki
ReentrantLock是jdk实现的重入锁,是AQS的经典实现之一,所以必须得懂AQS
https://github.com/969251639/study/wiki/AbstractQueueSysnchorized%E5%8E%9F%E7%90%86
ReentrantLock有两种锁,通过构造方法实现
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
第一个构造函数是直接new了一个NonfairSync,表示创建的锁时非公平锁
第二个构造函数是根据参数fair来创建公平锁或非公平锁
- 非公平锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {//锁
if (compareAndSetState(0, 1))//尝试cas修改state,修改成功则抢锁成功
setExclusiveOwnerThread(Thread.currentThread());//设置当前持有锁的线程
else//cas修改state不成功,则去竞争锁
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() &&//判断是否线程排队获取锁,如果有则跳到下一个重入判断,否则则表示还没有线程去竞争锁,尝试CAS修改下state
compareAndSetState(0, acquires)) {//尝试修改下state
setExclusiveOwnerThread(current);//设置当前线程持有锁
return true;
}
}
else if (current == getExclusiveOwnerThread()) {//判断是否能重入,也就是持有锁的线程是不是当前线程
int nextc = c + acquires;//重入次数+1
if (nextc < 0)//边界判断
throw new Error("Maximum lock count exceeded");
setState(nextc);//更新state值,即重入值
return true;
}
return false;
}
}
不管是公平锁还是非公平锁都继承自Sync
- Sync
Sync是ReentrantLock的内部类,用于对接AQS的底层实现,即继承AQS,重写它的几个模板方法
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();//获取state值
if (c == 0) {//还没有线程获取锁
if (compareAndSetState(0, acquires)) {//尝试cas修改state,修改成功则抢锁成功
setExclusiveOwnerThread(current);//设置当前持有锁的线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) {//判断是否能重入,也就是持有锁的线程是不是当前线程
int nextc = c + acquires;//重入次数+1
if (nextc < 0) // overflow 边界判断
throw new Error("Maximum lock count exceeded");
setState(nextc);//更新state值,即重入值
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {//尝试释放锁
int c = getState() - releases;//state减1(独占锁,releases=1)
if (Thread.currentThread() != getExclusiveOwnerThread())//不是持有锁的线程释放锁,抛出异常
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {//state减到0,表示锁释放成功,否则表示重入次数减1,但还没有完全释放锁
free = true;//释放锁成功标记
setExclusiveOwnerThread(null);//设置持有锁的线程为null
}
setState(c);//更新state值
return free;
}
protected final boolean isHeldExclusively() {//判断持有锁的线程是否是当前线程
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {//创建一个condition
return new ConditionObject();
}
final Thread getOwner() {//获取持有锁的线程,没有则返回null
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {//获取重入次数
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {//锁是否已经被占领
return getState() != 0;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {//序列化用
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
-
公平锁和非公平锁的区别
非公平锁在lock和tryLock的时候都会去尝试竞争锁,而不用进入到CLH队列,而公平锁则如果CLH队列不为空,则必须排队等待锁释放,所以非公平锁的吞吐量会大于公平锁,但缺点是有可能造成CLH后面的线程饥饿 -
其他方法
其他方法都是围绕上面创建的NonfairSync或FairSync来实现,来逐一看下:
public void lock() {//调用NonfairSync或FairSync竞争锁,成功返回,否则等待
sync.lock();
}
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();//创建一个条件等待队列
}
public int getHoldCount() {
return sync.getHoldCount();//获取锁的重入次数
}
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();//判断当前线程是否持有锁
}
public boolean isLocked() {
return sync.isLocked();//是否有线程获得锁
}
public final boolean isFair() {
return sync instanceof FairSync;//锁的实现是否是公平锁
}
protected Thread getOwner() {
return sync.getOwner();//获取持有锁的线程
}
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();//是否有线程在队列等待获取锁
}
public final int getQueueLength() {
return sync.getQueueLength();//获取等待队列的线程数,即有多少个线程在等待获取锁
}