一.什么是非公平锁?

先来聊聊非公平锁是啥,现在大家先回过头来看下面这张图。

如上图,现在线程1加了锁,然后线程2尝试加锁,失败后进入了等待队列,处于阻塞中。然后线程1释放了锁,准备来唤醒线程2重新尝试加锁。

注意一点,此时线程2可还停留在等待队列里啊,还没开始尝试重新加锁呢!

然而,不幸的事情发生了,这时半路杀出个程咬金,来了一个线程3!线程3突然尝试对ReentrantLock发起加锁操作,此时会发生什么事情?

很简单!线程2还没来得及重新尝试加锁呢。也就是说,还没来得及尝试重新执行CAS操作将state的值从0变为1呢!线程3冲上来直接一个CAS操作,尝试将state的值从0变为1,结果还成功了!

一旦CAS操作成功,线程3就会将“加锁线程”这个变量设置为他自己。给大家来一张图,看看这整个过程:

明明人家线程2规规矩矩的排队领锁呢,结果你线程3不守规矩,线程1刚释放锁,不分青红皂白,直接就跑过来抢先加锁了。

这就导致线程2被唤醒过后,重新尝试加锁执行CAS操作,结果毫无疑问,失败!

原因很简单啊!因为加锁CAS操作,是要尝试将state从0变为1,结果此时state已经是1了,所以CAS操作一定会失败!

一旦加锁失败,就会导致线程2继续留在等待队列里不断的等着,等着线程3释放锁之后,再来唤醒自己,真是可怜!先来的线程2居然加不到锁!

同样给大家来一张图,体会一下线程2这无助的过程:

上述的锁策略,就是所谓的非公平锁!
如果你用默认的构造函数来创建ReentrantLock对象,默认的锁策略就是非公平的。

在非公平锁策略之下,不一定说先来排队的线程就就先会得到机会加锁,而是出现各种线程随意抢占的情况。

那如果要实现公平锁的策略该怎么办呢?也很简单,在构造ReentrantLock对象的时候传入一个true即可:
ReentrantLock lock = new ReentrantLock(true)
此时就是说让他使用公平锁的策略,那么公平锁具体是什么意思呢?

二.什么是公平锁?

咱们重新回到第一张图,就是线程1刚刚释放锁之后,线程2还没来得及重新加锁的那个状态。

同样,这时假设来了一个线程3,突然杀出来,想要加锁。

如果是公平锁的策略,那么此时线程3不会跟个愣头青一样盲目的直接加锁。

他会先判断一下:咦?AQS的等待队列里,有没有人在排队啊?如果有人在排队的话,说明我前面有兄弟正想要加锁啊!

如果AQS的队列里真的有线程排着队,那我线程3就不能跟个二愣子一样直接抢占加锁了。

因为现在咱们是公平策略,得按照先来后到的顺序依次排队,谁先入队,谁就先从队列里出来加锁!

所以,线程3此时一判断,发现队列里有人排队,自己就会乖乖的排到队列后面去,而不会贸然加锁!

同样,整个过程我们用下面这张图给大家直观的展示一下:

上面的等待队列中,线程3会按照公平原则直接进入队列尾部进行排队。

接着,线程2不是被唤醒了么?他就会重新尝试进行CAS加锁,此时没人跟他抢,他当然可以加锁成功了。

然后呢,线程2就会将state值变为1,同时设置“加锁线程”是自己。最后,线程2自己从等待队列里出队。

整个过程,参见下图:

这个就是公平锁的策略,过来加锁的线程全部是按照先来后到的顺序,依次进入等待队列中排队的,不会盲目的胡乱抢占加锁,非常的公平。

三.小结

好了,通过画图和文字分析,相信大家都明白什么是公平锁,什么是非公平锁了!

不过要知道java并发包里很多锁默认的策略都是非公平的,也就是可能后来的线程先加锁,先来的线程后加锁。

而一般情况下,非公平的策略都没什么大问题,但是大家要对这个策略做到心里有数,在开发的时候,需要自己来考虑和权衡是要用公平策略还是非公平策略。

聊聊Java并发面试问题之公平锁与非公平锁是啥?的更多相关文章

  1. 并发系列4-大白话聊聊Java并发面试问题之公平锁与非公平锁是啥?【石杉的架构笔记】

  2. 并发系列5-大白话聊聊Java并发面试问题之微服务注册中心的读写锁优化【石杉的架构笔记】

  3. 并发系列3-大白话聊聊Java并发面试问题之谈谈你对AQS的理解?【石杉的架构笔记】

  4. 并发系列2-大白话聊聊Java并发面试问题之Java 8如何优化CAS性能?【石杉的架构笔记】

  5. 并发系列1----大白话聊聊Java并发面试问题之volatile到底是什么?【石杉的架构笔记】

  6. java并发库 Lock 公平锁和非公平锁

    jdk1.5并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,关于两者区别,java并发编程实践里面有解释 公平锁:   Threads acquir ...

  7. Java并发指南8:AQS中的公平锁与非公平锁,Condtion

    一行一行源码分析清楚 AbstractQueuedSynchronizer (二) 转自https://www.javadoop.com/post/AbstractQueuedSynchronizer ...

  8. Java并发编程锁之独占公平锁与非公平锁比较

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

  9. 【搞定 Java 并发面试】面试最常问的 Java 并发进阶常见面试题总结!

    本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.觉得内容不错 ...

随机推荐

  1. 11892 - ENimEN(博弈)

    UVA 11892 - ENimEN 题目链接 题意:给定n堆石头.两人轮流取,每次仅仅能取1堆的1到多个.假设上一个人取了一堆没取完.那么下一个人必须继续取这堆.取到最后一个石头的赢,问谁赢 思路: ...

  2. huawei校招测试题

    三道题两小时. 第一题,圈住所有点的长方形,很简单略过. 第二题:奇偶排序. 奇偶排序 描述: 输入若干(不超过1000个)非负整数数字,请先取出为奇数的数字按从大到小排序,再取出偶数从小到大进行排序 ...

  3. Android app身体质量指数(BMI)

    针对中国人的标准身高体重来測算,提示您身体的健康状况. 提示您是否应该锻炼.节食或者补充营养等.第一时间知道您的健康状况. 下载地址:http://android.myapp.com/myapp/de ...

  4. Mysql性能优化笔记

    一,索引 1.Innodb索引使用的是B+树 2.尽量简化where条件,比如不要出现 where id + 3 = 5,这无法使用索引 3.索引很大时,可以冗余一列来模拟哈希索引 4.小的表不需要使 ...

  5. hibernate 的分页查询

    hibernate的分页查询有个好处,就是不用管数据库方言.比如db2的分页查询很麻烦,但是用hibernate的方式,就完全不用管这些了 /* 使用HQL分页查询Customer信息 */ publ ...

  6. 利用CoreTelephony获取用户当前网络状态(判断2G,3G,4G)

    前言: 在项目开发当中,往往需要利用网络.而用户的网络环境也需要我们开发者去注意,根据不同的网络状态作相应的优化,以提升用户体验. 但通常我们只会判断用户是在WIFI还是移动数据,而实际上,移动数据也 ...

  7. IOS中调用系统拨打电话发送短信

    一.调用打电话界面 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat ...

  8. HDU4763 Theme Section —— KMP next数组

    题目链接:https://vjudge.net/problem/HDU-4763 Theme Section Time Limit: 2000/1000 MS (Java/Others)    Mem ...

  9. POJ3984 迷宫问题 —— BFS

    题目链接:http://poj.org/problem?id=3984 迷宫问题 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions ...

  10. JavaScript函数调用规则

    1. [代码][JavaScript]代码     JavaScript函数调用规则一 (1)全局函数调用:function makeArray( arg1, arg2 ){    return [t ...