“全栈2019”Java多线程第四十七章:判断锁是否为公平锁isFair()

难度

初级

学习时间

30分钟

适合人群

零基础

开发语言

Java

开发环境

  • JDK v11
  • IntelliJIDEA v2018.3

友情提示

  • 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
  • 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!

1.温故知新

前面在《“全栈2019”Java多线程第四十二章:获取线程与读写锁的保持数》一章中介绍了可重入读写锁ReentrantReadWriteLock的获取线程与读写锁保持数系列方法

《“全栈2019”Java多线程第四十三章:查询是否有线程在等待读写锁》一章中介绍了可重入读写锁ReentrantReadWriteLock的查询是否有线程正在等待获取读写锁hasQueuedThreads()方法、获取有多少个正在等待获取读写锁的线程getQueueLength()方法和查询指定线程是否正在等待获取读写锁的hasQueuedThread(Thread thread)方法。

《“全栈2019”Java多线程第四十四章:读锁不支持Condition》一章中介绍了可重入读写锁ReentrantReadWriteLock与Condition的关系,在读写锁中,写锁是支持Condition的,读锁是不支持Condition的,原因在于写锁在某一时刻最多只能被一个线程拥有,而读锁在某一时刻最多可以被多个线程拥有,对于读锁而言,其他线程没有必要等待获取读锁,等待唤醒是毫无意义的。

《“全栈2019”Java多线程第四十五章:查询Condition上的等待线程》一章中介绍了如何查询Condition上是否有线程正在等待和有多少线程正在等待。用锁的hasWaiters​(Condition condition)方法查询Condition上是否有线程正在等待,再用getWaitQueueLength​(Condition condition)方法获取Condition上等待的线程的个数。

《“全栈2019”Java多线程第四十六章:判断任意线程是否已持有写锁》一直中介绍了如何判断任意线程是否已持有写锁。通过ReentrantReadWriteLock的isWriteLocked()方法来判断写锁是否已被任意线程持有。

现在介绍如何判断锁是否为公平锁isFair()方法。

2.公平锁与非公平锁

《“全栈2019”Java多线程第二十八章:公平锁与非公平锁详解》一章中介绍了公平锁与非公平锁

以下是内容总结:

  • 公平锁和非公平锁其实说的是获取锁的机会是不是对每个等待线程都公平。
  • 公平锁就是获取锁的机会对每个等待线程都公平。
  • 非公平锁就是获取锁的机会对每个等待线程都不公平。
  • 隐式锁(即synchronized关键字用的锁)是非公平锁。
  • 显式锁默认是非公平锁。
  • 将显式锁非公平锁变成公平锁只需一步,在创建ReentrantLock对象时,给构造方法参数里传入true即可。

这里我们就先看看非公平锁。

首先,我们创建出读写锁:

然后,创建出读锁和写锁:

接着,创建实现了Runnable接口的匿名内部类对象:

先不着急实现run()方法。

先来创建出3个线程,并将实现了Runnable接口的匿名内部类对象传递给线程对象:

接着,启动线程:

再来实现run()方法。

先让线程获取到写锁:

获取到写锁之后,输出一句话:

在输出之前使当前线程睡1秒钟:

例子先写到这。

运行程序,执行结果:

从运行结果来看,不符合预期。

为什么不符合预期?

因为这3个线程都执行了一次任务,看似很公平,不像之前说的“显式锁默认是非公平锁”,所以此次运行结果不符合预期。

每个线程都只执行了一次任务,也只竞争了一次锁,看不出公平与不公平。

接下来,我们要让线程们不停地去竞争锁,再看看公不公平。

修改例子,将run()方法里面的内容用while循环包裹,这样做的目的就是为了不停地让线程们去竞争锁:

例子修改完毕。

运行程序,执行结果:

从运行结果来看,符合预期。我们看到每次都是同一线程拿到锁,其他线程都没拿到过,这锁也太不公平了。

我们可以通过isFair()方法来看看当前锁是否公平,下面就来介绍isFair()方法。

3.判断锁是否为公平锁isFair()方法

请问isFair()方法有什么用呢?

我们可以使用isFair()方法来判断锁是否为公平锁。

下面我们就来看看isFair()方法。

isFair()方法在ReentrantReadWriteLock类中的源码:

将注释翻译成中文:

中文注释全文:

如果此锁为公平锁,方法返回true,否则返回false。

去掉注释版:

isFair()方法作用是判断锁是否为公平锁,如果此锁为公平锁,方法返回true,否则返回false。

访问权限

public:isFair()方法是公开的。

boolean:isFair()方法返回boolean类型的值,如果此锁为公平锁,方法返回true,否则返回false。

isFair()方法只能被对象调用。

参数

无。

抛出的异常

无。

应用

下面,我们就来试试isFair()方法。

还是上一小节的例子,我们将输出isFair()方法的结果:

例子修改完毕。

运行程序,执行结果:

从运行结果来看,符合预期。

当前锁的确不是公平锁。

4.创建公平锁

将非公平锁变为公平锁只需一步,在创建锁(可重入锁和可重入读写锁)的时候,给构造方法参数里传入true即可。

还是上一小节例子。

看看之前创建锁对象的代码:

没有给构造方法参数里传入true,说明该锁是一个非公平锁。

下面,我们将其变为公平锁,只需给构造方法参数中传入true即可:

例子改写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。

当前锁已经是公平锁了。而且每个线程获取到锁的机会平等。

最后,希望大家可以把这个例子照着写一遍,然后再自己默写一遍,方便以后碰到类似的面试题可以轻松应对。

祝大家编码愉快!

GitHub

本章程序GitHub地址:https://github.com/gorhaf/Java2019/tree/master/Thread/ReadWriteLock/ReentrantReadWriteLock

总结

  • isFair()方法作用是判断锁是否为公平锁,如果此锁为公平锁,方法返回true,否则返回false。

至此,Java中判断锁是否为公平锁相关内容讲解先告一段落,更多内容请持续关注。

答疑

如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。

上一章

“全栈2019”Java多线程第四十六章:判断任意线程是否已持有写锁

下一章

“全栈2019”Java多线程第四十八章:读写锁实战高并发容器

学习小组

加入同步学习小组,共同交流与进步。

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。

全栈工程师学习计划

关注我们,加入“全栈工程师学习计划”。

版权声明

原创不易,未经允许不得转载!

了解更多
举报
评论 0