公平锁与非公平锁实现原理"/>
ReentrantLock公平锁与非公平锁实现原理
ReentrantLock公平锁与非公平锁的实现原理
ReentrantLock是J.U.C包下的一个类,默认是非公平的
public class ReentrantLock implements Lock, java.io.Serializable {// 内部类private final Sync sync;public ReentrantLock() {// 默认使用非公平锁sync = new NonfairSync();}// 可通过传入参数(true)的形式使用公平锁public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}
其中内部类 Sync 继承了 AQS
abstract static class Sync extends AbstractQueuedSynchronizer {//...
}
而 NonfairSync 与 FairSync 都是继承自 Sync,也均是内部类
static final class NonfairSync extends Sync
static final class FairSync extends Sync
一. 非公平锁实现原理
我们先来看一下我们常用的使用方式 ReentrantLock 实现,一般都是直接 new 一个对象,然后通过 lock() 方法获取锁,它是怎么实现的呢,代码如下:
// 1. 获取对象,默认非公平public ReentrantLock() {sync = new NonfairSync();}// 2. 调用lock() 方法public void lock() {sync.lock();}// 3. 调用非公平内部类实现的 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);}// 其他方法。。。}// acquire(1) 方法内部逻辑public final void acquire(int arg) {if (!tryAcquire(arg) && // 尝试获取锁acquireQueued(addWaiter(Node.EXCLUSIVE), arg))// 调用AQS 同步方法selfInterrupt();}
非公平锁的 acquire(int arg) ,逻辑比较简单,源码如下
protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}/*** 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();// 若锁状态为0,则直接执行获取锁逻辑if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}// 若锁已经有线程执行,则判断是否为当前线程,若是则state + 1, 这也是可重入的实现else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
二. 公平锁实现原理
接下来我们一起看下公平锁的源码有何不同
// 传入 true 则会使用公平锁实现 FairSyncpublic ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}static final class FairSync extends Sync {// lock方法直接调用 acquire 方法final void lock() {acquire(1);}// ...}
acquire 方法是公用的,主要看一下内部的 tryAcquire 方法,直接上源码:
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;}}
相信大家都已经看出来了它们的差异,接下来我再把它们不同的地方圈出来
三. 公平与非公平锁的对比
何为公平,何为非公平,在这个标榜着人人平等的社会,排队买东西大家都比较熟悉,不管是谁都得排队,先的来先买(除特殊情况)。
ReentrantLock也是相同的思想,引入了阻塞队列来实现排队等候,先来先执行,后来则排队(FIFO),所以是公平的。
那是什么是非公平呢,有人插队嘛,对吧,都插队了还谈什么公平呢,ReentrantLock的非公平锁就是不考虑阻塞队列的情况下直接获取锁。
看看源码上的区别大家就一目了然了:
// 非公平锁final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}// 公平锁final void lock() {acquire(1);}
非公平的进来先看看能不能拿到锁,如果拿到的话转身就溜,也不看看有没有其它线程在排队等待
再来看下 acquire 方法的流程
public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}// 公平锁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;}// 非公平锁protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}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) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
可以看出来,非公平锁在 lock() 方法里多了直接获取锁的逻辑
if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());
在 tryAcquire(int acquires) 方法里少了判断阻塞的逻辑,而公平锁首先会考虑是否有线程在排序等候,主要方法 hasQueuedPredecessors()
// FairSync
if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;
}// NonfairSync
if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;
}
锁的释放公平与非公平是一样的
如有错误的地方还望大家指正
更多推荐
ReentrantLock公平锁与非公平锁实现原理
发布评论