本篇文章小编给大家分享一下Java公平锁和非公平锁代码区别一览,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。
正文
公平锁:每个线程获取锁的顺序是按照线程访问锁的先后顺序获取的,最前面的线程总是最先获取到锁。
非公平锁:每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,所有线程会竞争获取锁。
举个例子:公平锁就像开车经过收费站一样,所有的车都会排队等待通过,先来的车先通过,
如下图所示:
通过收费站的顺序也是先来先到,分别是张三、李四、王五,这种情况就是公平锁。 而非公平锁相当于,来了一个强行加塞的老司机,它不会准守排队规则,来了之后就会试图强行加塞,如果加塞成功就顺利通过,当然也有可能加塞失败,如果失败就乖乖去后面排队,这种情况就是非公平锁。
应用场景
在 Java 语言中,锁 synchronized 和 ReentrantLock 默认都是非公平锁,当然我们在创建 ReentrantLock 时,可以手动指定其为公平锁,但 synchronized 只能为非公平锁。
ReentrantLock 默认为非公平锁可以在它的源码实现中得到验证,如下源码所示:
当使用 new ReentrantLock(true) 时,可以创建公平锁,如下源码所示:
公平和非公平锁代码演示
接下来我们使用 ReentrantLock 来演示一下公平锁和非公平锁的执行差异,首先定义一个公平锁,开启 3 个线程,每个线程执行两次加锁和释放锁并打印线程名的操作,
如下代码所示:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockFairTest { static Lock lock = new ReentrantLock(true); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 3; i++) { new Thread(() -> { for (int j = 0; j < 2; j++) { lock.lock(); System.out.println("当前线程:" + Thread.currentThread() .getName()); lock.unlock(); } }).start(); } } }
以上程序的执行结果如下图所示:
接下来我们使用非公平锁来执行上面的代码,具体实现如下:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockFairTest { static Lock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 3; i++) { new Thread(() -> { for (int j = 0; j < 2; j++) { lock.lock(); System.out.println("当前线程:" + Thread.currentThread() .getName()); lock.unlock(); } }).start(); } } }
以上程序的执行结果如下图所示:
从上述结果可以看出,使用公平锁线程获取锁的顺序是:A -> B -> C -> A -> B -> C,也就是按顺序获取锁。而非公平锁,获取锁的顺序是 A -> A -> B -> B -> C -> C,原因是所有线程都争抢锁时,因为当前执行线程处于活跃状态,其他线程属于等待状态(还需要被唤醒),所以当前线程总是会先获取到锁,所以最终获取锁的顺序是:A -> A -> B -> B -> C -> C。
执行流程分析
公平锁执行流程
获取锁时,先将线程自己添加到等待队列的队尾并休眠,当某线程用完锁之后,会去唤醒等待队列中队首的线程尝试去获取锁,锁的使用顺序也就是队列中的先后顺序,在整个过程中,线程会从运行状态切换到休眠状态,再从休眠状态恢复成运行状态,但线程每次休眠和恢复都需要从用户态转换成内核态,而这个状态的转换是比较慢的,所以公平锁的执行速度会比较慢。
非公平锁执行流程
当线程获取锁时,会先通过 CAS 尝试获取锁,如果获取成功就直接拥有锁,如果获取锁失败才会进入等待队列,等待下次尝试获取锁。这样做的好处是,获取锁不用遵循先到先得的规则,从而避免了线程休眠和恢复的操作,这样就加速了程序的执行效率。
公平锁和非公平锁的性能测试结果如下:
从上述结果可以看出,使用非公平锁的吞吐率(单位时间内成功获取锁的平均速率)要比公平锁高很多。
优缺点分析
公平锁的优点是按序平均分配锁资源,不会出现线程饿死的情况,它的缺点是按序唤醒线程的开销大,执行性能不高。 非公平锁的优点是执行效率高,谁先获取到锁,锁就属于谁,不会“按资排辈”以及顺序唤醒,但缺点是资源分配随机性强,可能会出现线程饿死的情况。
忍者必须死34399账号登录版 最新版v1.0.138v2.0.72
下载勇者秘境oppo版 安卓版v1.0.5
下载忍者必须死3一加版 最新版v1.0.138v2.0.72
下载绝世仙王官方正版 最新安卓版v1.0.49
下载Goat Simulator 3手机版 安卓版v1.0.8.2
Goat Simulator 3手机版是一个非常有趣的模拟游
Goat Simulator 3国际服 安卓版v1.0.8.2
Goat Simulator 3国际版是一个非常有趣的山羊模
烟花燃放模拟器中文版 2025最新版v1.0
烟花燃放模拟器是款仿真的烟花绽放模拟器类型单机小游戏,全方位
我的世界动漫世界 手机版v友y整合
我的世界动漫世界模组整合包是一款加入了动漫元素的素材整合包,
我的世界贝爷生存整合包 最新版v隔壁老王
我的世界MITE贝爷生存整合包是一款根据原版MC制作的魔改整