ReentrantLock公平锁与非公平锁实现原理

编程入门 行业动态 更新时间:2024-10-06 21:27:04

ReentrantLock<a href=https://www.elefans.com/category/jswz/34/1754813.html style=公平锁与非公平锁实现原理"/>

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 {//...
}

NonfairSyncFairSync 都是继承自 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公平锁与非公平锁实现原理

本文发布于:2024-02-25 07:59:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1698302.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:公平   与非   原理   ReentrantLock

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!