Java并发之ReentrantLock源码篇
一、ReentrantLock
ReentrantLock
是一个可重入且独占式的锁,和 synchronized
关键字类似。不过,ReentrantLock
更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。
1. 继承关系
ReentrantLock
实现了Lock
接口,Lock
接口中定义了lock
与unlock
相关操作,并且还存在newCondition
方法,表示生成一个条件。
public class ReentrantLock implements Lock, java.io.Serializable { ... }
|
Lock接口主要方法如下:
2. 内部类
ReentrantLock
总共有三个内部类,并且三个内部类是紧密相关的。
Sync
,继承自AbstractQueueSynchronizer
抽象类,
FairSync
,继承自Sync
类
NonfairSync
,继承自Sync
类
(1) Sync
通过下面的源码可以看到,Sync
其实就是重写了AbstractQueuedSynchronizer
中的方法,其实本质上还是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(); if (c == 0) { if (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; }
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() {
return getExclusiveOwnerThread() == Thread.currentThread(); }
final ConditionObject newCondition() { return new ConditionObject(); }
final Thread getOwner() { 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); } }
|
(2) NonfairSync
NonfairSync
类继承了Sync
类,表示采用非公平策略获取锁。从下面的源码可以看出:
每次lock
时都会尝试获取锁,而不是按照公平等待的原则进行等待,让等待时间最久的线程获得锁。
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); } }
|
(3) FairSync
FairSync
类也继承了Sync
类,表示采用公平策略获取锁。从下面的源码可知:
当资源空闲时,它总是会先判断sync
队列(即AbstractQueuedSynchronizer
中的数据结构)是否有等待时间更长的线程,如果存在,则将该线程加入到等待队列的尾部,实现了公平获取原则。
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; } }
|
3. 构造函数
默认的构造函数采用的是非公平策略获取锁,另外还可以通过传递参数来决定采用公平策略或者是非公平策略,参数为true表示公平策略,参数为false则采用非公平策略。
public ReentrantLock() { sync = new NonfairSync(); }
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
|
4. 核心逻辑
通过分析ReentrantLock的源码,可知对其操作都转化为对Sync对象的操作,由于Sync继承了AQS,所以基本上都可以转化为对AQS的操作。如将ReentrantLock的lock函数转化为对Sync的lock函数的调用,而具体会根据采用的策略(如公平策略或者非公平策略)的不同而调用到Sync的不同子类。
二、完整源码
以下源码版本为JDK8。
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; 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) 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() { return getExclusiveOwnerThread() == Thread.currentThread(); }
final ConditionObject newCondition() { return new ConditionObject(); }
final Thread getOwner() { 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); } }
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; } }
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(); }
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 boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); }
public final int getQueueLength() { return sync.getQueueLength(); }
protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); }
public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); }
public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); }
protected Collection<Thread> getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); }
public String toString() { Thread o = sync.getOwner(); return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]"); } }
|