作者 | 王磊

来源 | Java中文社群(ID:javacn666)

转载请联系授权(微信ID:GG_Stone)

在 Java 中 synchronized 和 ReentrantLock 默认使用的都是非公平锁,而它们采用非公平锁的原因都是一致的,都是为了提升程序的性能。那为什么非公平锁就能提升性能呢?接下来我们一起来看。

非公平锁

非公平锁:每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,任何线程在某时刻都有可能直接获取并拥有锁。这就好比磊哥去加油,到了加油站之后发现前面有人在加,于是我就在车里刷起了抖音,过了一会,前面的车加完油走了,但磊哥没注意到,还在车里愉快的刷着抖音。然而此时加油站又来了一辆车,发现有空闲的油枪,于是就抢先在磊哥之前把油加了。这里的油枪就是锁,没有按照到达的先后顺序得到油枪,这就是非公平锁。

公平锁

公平锁:每个线程获取锁的顺序是按照线程访问锁的先后顺序获取的,最前面的线程总是最先获取到锁。这就好像上高速排队过收费站一样,所有的车要排队等待通行,最先来的车最先通过收费站。

性能对比

公平锁和非公平锁的性能测试结果如下,以下测试数据来自于《Java并发编程实战》:

从上述结果可以看出,使用非公平锁的吞吐率(单位时间内成功获取锁的平均速率)要比公平锁高很多。

性能分析

以上测试数据虽然说明了结果,但并不能说明为什么非公平锁的性能会更高?所以,接下来,我们通过分析公平锁和非公平的执行流程,来得到这个问题的答案。

公平锁执行流程

获取锁时,先将线程自己添加到等待队列的队尾并休眠,当某线程用完锁之后,会去唤醒等待队列中队首的线程尝试去获取锁,锁的使用顺序也就是队列中的先后顺序,在整个过程中,线程会从运行状态切换到休眠状态,再从休眠状态恢复成运行状态,但线程每次休眠和恢复都需要从用户态转换成内核态,而这个状态的转换是比较慢的,所以公平锁的执行速度会比较慢。

用户态 & 内核态

用户态(User Mode):当进程在执行用户自己的代码时,则称其处于用户运行态。内核态(Kernel Mode):当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态,此时处理器处于特权级最高的内核代码中执行。

为什么分内核态和用户态?

假设没有内核态和用户态之分,程序就可以随意读写硬件资源了,比如随意读写和分配内存,这样如果程序员一不小心将不适当的内容写到了不该写的地方,很可能就会导致系统崩溃。

而有了用户态和内核态的区分之后,程序在执行某个操作时会进行一系列的验证和检验之后,确认没问题之后才可以正常的操作资源,这样就不会担心一不小心就把系统搞坏的情况了,也就是有了内核态和用户态的区分之后可以让程序更加安全的运行,但同时两种形态的切换会导致一定的性能开销。

非公平锁执行流程

当线程获取锁时,会先通过 CAS 尝试获取锁,如果获取成功就直接拥有锁,如果获取锁失败才会进入等待队列,等待下次尝试获取锁。这样做的好处是,获取锁不用遵循先到先得的规则,从而避免了线程休眠和恢复的操作,这样就加速了程序的执行效率。

比如前几天磊哥去一个小营业厅办理网络移机的业务,去了之后发现前面有人在办业务,于是磊哥就告诉前面(办理业务)的小姐姐,“我门口休息一下,您等会办理完业务,麻烦去门口叫一下我”,小姐姐人也比较好,一口就答应下来了。

但在小姐姐办完业务之后叫我,和我回到柜台办理业务之间,是有一段空闲时间的,这和等待队列中的线程被唤醒和恢复执行之间是有一段空闲时间是一样的,而在这个空闲的时间中,营业厅又来了一个老李头来交话费,等老李交完话费,我恰好也刚回来可以直接办理业务了,这样就是一个“三赢”的局面。

老李头不用排在我后面等着缴话费,我也不用等老李头交完话费再办理移机,而且在单位时间内提高了营业员办理业务的效率,她也能早早的回家,这就是所谓的“三赢”。在更短的时间内执行更多的任务,这就是非公平锁的优势

总结

本文我们介绍了公平锁和非公平锁的定义以及执行流程,从二者执行流程的细节可以看出,非公平锁因为不用按(顺)序执行,所以后来的锁也可以直接尝试获得锁,没有了阻塞和恢复执行的步骤,所以它的性能会更高。

本系列原创文章推荐

1.线程的故事:我的3位母亲成就了优秀的我!

2.线程池的7种创建方式,强烈推荐你用它...

3.轻量级锁一定比重量级锁快吗?

4.这样终止线程,竟然会导致服务宕机?

5.漫画:如何证明sleep不释放锁,而wait释放锁?

6.池化技术到达有多牛?看了这个对比吓我一跳!

7.求求你,别再用wait和notify了!

8.Semaphore自白:限流器用我就对了!

9.CountDownLatch:别浪,等人齐再团!

10.CyclicBarrier:人齐了,老司机就发车了!

11.Java中用户线程和守护线程区别这么大?

12.ThreadLocal不好用?那是你没用对!

13.ThreadLocal内存溢出代码演示和原因分析!

14.SimpleDateFormat线程不安全的5种解决方案!

15.synchronized 加锁 this 和 class 的区别!

16.synchronized 优化手段之锁膨胀机制!

17.synchronized 中的 4 个优化,你知道几个?

18.ReentrantLock 中的 4 个坑!


图解:为什么非公平锁的性能更高?相关推荐

  1. 公平锁和非公平锁的性能差异

    公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁. 优点:所有的线程都能得到资源,不会饿死在队列中. 缺点:吞吐量会下降很多,队列里面除了第一个线程, ...

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

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

  3. java公平锁和非公平锁_java并发编程学习之再谈公平锁和非公平锁

    在java并发编程学习之显示锁Lock里有提过公平锁和非公平锁,我们知道他的使用方式,以及非公平锁的性能较高,在AQS源码分析的基础上,我们看看NonfairSync和FairSync的区别在什么地方 ...

  4. 图解ReentrantLock公平锁和非公平锁实现

    概述 ReentrantLock是Java并发中十分常用的一个类,具备类似synchronized锁的作用.但是相比synchronized, 它具备更强的能力,同时支持公平锁和非公平锁. 公平锁: ...

  5. 公平锁非公平锁的实际使用_理解ReentrantLock的公平锁和非公平锁

    学习AQS的时候,了解到AQS依赖于内部的FIFO同步队列来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成一个Node对象并将其加入到同步队列,同时会阻塞当 ...

  6. 浅谈ReentrantLock的公平锁和非公平锁的区别

    前言 最近在看java并发编程这本书,已经看了点ReentrantLock的源码,以及之前有面试官问,公平锁和非公平锁有啥区别,我就只是从源码层面说了一下区别,但在性能上也有区别,今天就来说道说道. ...

  7. Java面试突击:公平锁和非公平锁有什么区别?

    从公平的角度来说,Java 中的锁总共可分为两类:公平锁和非公平锁.但公平锁和非公平锁有哪些区别?孰优孰劣呢?在 Java 中的应用场景又有哪些呢?接下来我们一起来看. 正文公平锁:每个线程获取锁的顺 ...

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

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

  9. java公平索非公平锁_java中的非公平锁不怕有的线程一直得不到执行吗

    首先来看公平锁和非公平锁,我们默认使用的锁是非公平锁,只有当我们显示设置为公平锁的情况下,才会使用公平锁,下面我们简单看一下公平锁的源码,如果等待队列中没有节点在等待,则占有锁,如果已经存在等待节点, ...

最新文章

  1. 170728、单例模式的三种水平代码
  2. 彻彻底底了解回调函数
  3. hibernate框架 最新_java框架,使用最频繁的9个程序!
  4. IOS开发(104)之程序执行状态更改
  5. Python中的+=
  6. STM32的SRAM调试
  7. MYSQ--SHOW PROFILE Syntax and useing
  8. 中怎么构建ebug模式_Mybatis的设计模式运用
  9. 非常好用的自助建站程序整站源码 内置几十种站
  10. 【已解决】Python将网页内容保存为PDF (url转pdf)
  11. 【Linux】3.0Linux进程概念
  12. MySQL高手篇:精妙SQL语句介绍
  13. 【机器学习基础】三层神经网络
  14. 简单css实现表格头部固定
  15. VMware下载及安装(附带下载地址)
  16. AirDisk产品A6/A4支持OTG数据线连接到手机吗
  17. java/php/net/python交互体验的电影评价系统设计
  18. Linux多线程学习(七)sched_yield
  19. Python--文件的读写
  20. C++下OPENCV驱动调用海康GigE工业相机

热门文章

  1. 微人事项目实战的数据库脚本_EMP微前端实战之cocos2d线上项目
  2. android手机微信收藏功能实现,Android模仿微信收藏文件的标签处理功能
  3. V$LICENSE表结构
  4. Public Sale【博弈】
  5. 前端页面:一直报Cannot set property 'height' of undefined
  6. Android Sqlite
  7. JAVA学习--集合的遍历
  8. UbuntuKylin安装SUN JDK1.7
  9. Centos下lnmp编译安装详细过程
  10. 大道五目Flash英文版(Renju Problems)程序分析之禁手判断