一、ReentranLock的三个内部静态类FairSync、NonFairSync、Sync之间的关系
FairSync和NonFairSync都是继承Sync这个抽象类;
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
/**
*1、获取当前线程
*2、获取当前线程的state
*3、如果state为零,那么表示当前线程在此之前并没有获得锁,因此需要竞争锁去第4步,
如果当前的线程的state大于零,那么表示这个线程拥有锁,只是再一次申请锁转向第6步
*4、通过CAS的方式来判断当前线程是否获得锁,如果compareAndSetState(0, acquires)返回true,
那么线程获得锁转向第5步,否则转向第7步
*5、通过setExclusiveOwnerThread()方法将当前线程设置成独占锁的那个线程,返回true
*6、如果当前线程是独占锁的那个线程,那么我们将state = state+aquires,返回true
*7、以上步骤如果执行完了,没有返回,那么表示锁竞争失败,所以返回false
*/
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;
}
//
/**
*释放锁和之前的重入锁的过程是差不多的
*1、获取当前线程
*2、判断当前线程是否是独占锁的那个线程
*3、如果是,那么我们将state设置成0
*4、同时我们将setExclusiveOwnerThread设置成null,表示当前没有线程独占该锁
*5、回写state
*6、释放成功返回true
*7、返回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;
}
//如果占有锁的线程就是当前线程那么返回true
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();
}
//返回独占锁的那个线程,如果state=0,则没有线程占有锁,如果state>0,则返回独占锁的线程
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
/**
*如果占有锁的线程是当前线程返回true,
*那么我们就返回state就行,state表示ReentranLock重入的次数
*/
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
//如果当前线程的state为零,那么表示线程并没有获得锁,返回false,否则返回true
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
}
}
NofairSync类
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/***
*通过CAS的方式去竞争锁,如果竞争成功则将当前线程设置成独占锁的那个线程,
*反之,调用acquire(1),这个方法后面具体解析
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
//尝试去获得锁,使用的是父类Sync的nonFairTryAcquire()
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
FairSync类
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* 公平锁实现了一个尝试获取锁的方法,
* 1、获取当前线程,以及当前线程的state
* 2、如果当前线程的state为零,那么表明当前线程之前并没有获得锁,那么转向步骤3,
* 如果state不为零,则转向当前锁采用重入的方式,只要对state+1这个变量进行修改就可以了
* 3、首先判断hasQueuedPredecessors(),如果返回false,
* 则表明该线程之前还有线程的前面没有等待队列,执行第4步。
* 如果返回true,那么表示这个线程之前还有线程在等待,尝试获取锁失败,那么则结束返回false
* 4、如果前面没有线程在等待,那么当前线程就采用CAS的方式获取锁,
* 获取成功则将当前线程设置为独占当前锁的线程,如果设置失败,那么将返回false
*
*
*/
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;
}
}
总结:
- 对于lock(),FairSync相较于NonFairSync少了使用尝试使用CAS设置state获取锁的步骤
- 对于tryquire(),FairSync在尝试获取锁的时候需要判断等待队列是否有线程在等待,而NonSync直接使用CAS设置state的方式将线程设置成独占锁的线程。
ReentranLock的构造方法和使用建议
ReentranLock分为公平锁和非公平锁;我们可以看一下公平锁和非公平锁是如何定义的
1、公平锁定义方式
Lock fairLock = new ReentranLock(true);
2、非公平锁定义方式
Lock unfairLock = new ReentranLock();
//或者
Lock unfairLock = new ReentranLock(false);
3、我们看一下ReentranLock构造方法是如何定义一个公平锁的
private final Sync sync;
//非公平锁构造器
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 公/非公平平锁构造器
* fair = true 时返回一个new FairSync()
* fair = false 时返回一个NonFairSync()
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
4、ReentranLock类的lock方法
/**
* sync根据前面构造器定义的方式返回的对象会自动的去调用子类
* 如果sync引用的是FairSync,那么就调用FairLock的lock()方法
* 如果引用的是NonFairSync,那么就调用FairLock的lock()方法
*
*/
public void lock() {
sync.lock();
}
5、FairSync和NonFairSync获取锁的方式的差异性
//FairSync 直接调用调用acquire()方法获取锁
final void lock() {
acquire(1);
}
/***
*通过CAS的方式去竞争锁,如果竞争成功则将当前线程设置成独占锁的那个线程,
*反之,调用acquire(1),这个方法后面具体解析
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
这里我们看到lock方法调用了acquire方法,但是我们发现FairSync和NonFairSync以及Sync这个类中都没有acquire()方法。因此我们想到去Sync的超类AbstractQueuedSynchronizer找到这个方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//AbstractQueuedSynchronizer的tryAcquire(int arg)方法
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
//
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);
}
}
//
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;
}