转载:https://www.jianshu.com/p/5104cd94dbe0

1、什么是公平锁与非公平锁

公平锁:公平锁就是保障了多线程下各线程获取锁的顺序,先到的线程优先获取锁。
非公平锁:非公平锁则无法提供这个保障(先到的线程优先获取锁)。

2、ReentrantLock如何实现公平与非公平

Java并发包下面的ReentrantLockReadWriteLock默认都是非公平模式

下面我们就来一起看看ReentrantLock是如何实现公平与非公平的。

ReentrantLock实现了Lock接口。提供了下面2个构造方法

public ReentrantLock() {sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();
}

默认构造的是非公平锁NonfairSync。
NonfairSync和FairSync都是ReentrantLock的内部类,且继承ReentrantLock的内部抽象类Sync。

// 公平锁
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 主要区别:有hasQueuedPredecessors方法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;}
}// 非公平锁
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 主要区别:没有hasQueuedPredecessors方法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;
}

二者的主要去别在于是否有hasQueuedPredecessors方法,我们看下hasQueuedPredecessors的源码。该方法返回“队列中是否存在一个线程(先于当前线程)”,如果存在话,当前线程就要加入到队列的尾部。

* @return {@code true} if there is a queued thread preceding the*         current thread, and {@code false} if the current thread*         is at the head of the queue or the queue is empty* @since 1.7*/
public final boolean hasQueuedPredecessors() {// The correctness of this depends on head being initialized// before tail and on head.next being accurate if the current// thread is first in queue.Node t = tail; // Read fields in reverse initialization orderNode h = head;Node s;return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}

网上有这一张很棒的图:

公平锁与非公平锁

结合这张图,二者的区别更明显。
公平锁就是在获取锁之前会先判断等待队列是否为空或者自己是否位于队列头部,该条件通过才能继续获取锁。

在结合兔子喝水的图分析,非公平锁获取所得顺序基本决定在9、10、11这三个事件发生的先后顺序,

  • 1、若在释放锁的时候总是没有新的兔子来打扰,则非公平锁等于公平锁;
  • 2、若释放锁的时候,正好一个兔子来喝水,而此时位于队列头的兔子还没有被唤醒(因为线程上下文切换是需要不少开销的),此时后来的兔子则优先获得锁,成功打破公平,成为非公平锁;

其实对于非公平锁,只要线程进入了等待队列,队列里面依然是FIFO的原则,跟公平锁的顺序是一样的。因为公平锁与非公平锁的release()部分代码是共用AQS的代码。

public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;
}/*** Wakes up node's successor, if one exists.*/
private void unparkSuccessor(Node node) {/** If status is negative (i.e., possibly needing signal) try* to clear in anticipation of signalling.  It is OK if this* fails or if status is changed by waiting thread.*/int ws = node.waitStatus;if (ws < 0)compareAndSetWaitStatus(node, ws, 0);/** Thread to unpark is held in successor, which is normally* just the next node.  But if cancelled or apparently null,* traverse backwards from tail to find the actual* non-cancelled successor.*/Node s = node.next;if (s == null || s.waitStatus > 0) {s = null;for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0)s = t;}if (s != null)LockSupport.unpark(s.thread);
}

3、公平锁与非公平锁性能对比

非公平锁的效率高于公平锁:上文说到的线程切换的开销,其实就是非公平锁效率高于公平锁的原因,因为非公平锁减少了线程挂起的几率,后来的线程有一定几率逃离被挂起的开销。

公平锁和非公平锁-ReentrantLock是如何实现公平、非公平的相关推荐

  1. 6※、线程同步、同步锁、同步代码块的使用、同步锁释放的时机、ReentrantLock可重入锁、公平锁与非公平锁的区别、什么是死锁、线程间的通信(生产者和消费者模式)

    线程锁 1.※线程的同步:(要确保对象锁是一致的) 1.未使用同步锁的抢票 2.使用了同步锁的抢票 3.线程-同步代码块的使用 4.同步方法和代码块的区别 5.同步锁释放的时机 练习:多线程生产手机 ...

  2. java投票锁_Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...

  3. java 共享锁 独占锁_Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家取排队本着先来 ...

  4. java -锁(公平、非公平锁、可重入锁【递归锁】、自旋锁)

    1.公平锁.非公平锁 2.可重入锁(递归锁) 3.自旋锁 AtomicReference atomicReference = new AtomicReference();//原子引用线程 下面代码5秒 ...

  5. 可重入锁/不可重入锁,公平锁/非公平锁,乐观锁/悲观锁,独享锁/共享锁,偏向锁/轻量级锁/重量级锁,分段锁,自旋锁

    在并发编程中,会涉及到各种各样的锁,这篇文章主要介绍各种锁的分类以及作用. 介绍的内容如下: 可重入锁/不可重入锁 公平锁/非公平锁 乐观锁/悲观锁 独享锁/共享锁 偏向锁/轻量级锁/重量级锁 分段锁 ...

  6. 第二季:5公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁【Java面试题】

    第二季:5值传递和引用传递[Java面试题] 前言 推荐 值传递 说明 题目 24 TransferValue醒脑小练习 第二季:5公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自 ...

  7. 悲观|乐观锁、自旋|互斥锁、公平|非公平锁

    解析锁--悲观|乐观锁.自旋|互斥锁.公平|非公平锁 悲观锁 总认为最坏的情况可能会出现,即认为数据很可能会被他人修改,因此在持有数据时总是先把资源或数据锁住.这样其他线程要请求这个资源时就会阻塞,直 ...

  8. Juc07_乐观锁和悲观锁、公平锁和非公平锁、递归锁(可重入锁)、死锁及排查、自旋锁

    文章目录 ①. 乐观锁和悲观锁 ②. 公平锁和非公平锁 ③. 可重入锁(又名递归锁) ④. 死锁及排查 ⑥. 自旋锁 ①. 乐观锁和悲观锁 ①. 悲观锁(synchronized关键字和Lock的实现 ...

  9. JUC-9.“锁”事(显式锁与隐式锁/悲观锁与乐观锁/公平锁与非公平锁/可重入锁/读写锁(独占/共享/降级)/邮戳锁/死锁)、锁升级

    目录 一.悲观锁与乐观锁 1.1 悲观锁 1.2 乐观锁 二.公平锁与非公平锁 2.1 为什么会有公平锁/非公平锁的设计为什么默认非公平? 2.2 如何选择使用哪种锁? 三.可重入锁(又名递归锁) 3 ...

  10. Java中的锁机制 -- 乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、锁粗化、锁消除

    文章目录 1. Java中的锁机制 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 可重入锁(递归锁) 1.5 读写锁 1.6 公平锁 1.7 非公平锁 1.8 共享锁 1.9 独占锁 1.1 ...

最新文章

  1. nginx的root alias 指令
  2. leetcode 225. 用队列实现栈(维护两个队列用于倒替元素,使用和1进行按位与,实现队列切换)
  3. vs 不能自动 析构函数_深入理解C++虚函数的override、overload与hide以及虚析构函数...
  4. tomcat启动war包_不用下载tomcat,maven插件直接运行war包,真香
  5. Linux操作系统使用基础03:Linux文件权限与目录配置
  6. bzoj2208: [Jsoi2010]连通数
  7. 【kmp】POJ-3461 Oulipo
  8. EasyUI的DataGrid 打印导出
  9. php access 所有表,Oracle|sql server|access 数据库里的所有表名,字段名
  10. android手机 无线充电,无线充电手机有哪些?支持无线充电的手机推荐
  11. 集合涉及到的排序方式
  12. MongoDB下载、安装和配置教程
  13. R绘图| Kaplan-Meier曲线及美化
  14. linux堡垒机开源软件,几款开源的堡垒机
  15. JavaWeb网上图书商城
  16. Android日期格式化英文,android – 将日期从默认语言环境转换为英语语言环境
  17. mq5 EA模板及双均线交叉策略EAdemo
  18. 联想T440怎么把原装Win8或Win10换成Win7系统
  19. 快刀初试:Spark GraphX在淘宝的实践
  20. 【Pandas】解决在pandas中的两个正数相乘结果为负值

热门文章

  1. CAN帧格式(标准帧、拓展帧)
  2. mysql 阿里_详细解读阿里手册之MySQL
  3. VS2017中调试PSINS算法报错的解决办法
  4. Halcon 学习之焊点提取
  5. 利用空闲时间挣钱的兼职
  6. layui实现动态获取两级联动数据
  7. 【数据结构与算法】03 链表(基础知识+面试高频leetcode题目)
  8. 根据某城市普通出租车收费标准编写程序对车费进行计算。
  9. 【考研线代】五. 特征值和特征向量
  10. FPGA和外围接口-第一章 爱上FPGA(1.1、1.2)