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

article/2025/9/27 6:23:30

前言

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

公平与非公平

ReentrantLock的构造函数中提供了两种选择,默认创建非公平锁,也可以指定创建公平锁。
在公平锁上,线程将按照他们发出的请求顺序来获取锁,如果有另外一个线程持有这个锁或者有其他线程在队列中等待这个锁,那么新发出请求的线程就会被放到队列中。
在非公平锁上,允许“插队”:当一个线程请求非公平的锁时,如果在发出请求的同时该锁的状态变为可用,这个线程就会跳过队列中所有等待线程直接抢到这个锁。只有当锁被某个线程持有的时候,新发出请求的线程才会被放入队列中。

如何选择公平或非公平锁

为什么会有公平和非公平之分呢?我们都普遍认为一个公平的世界是一个稳定而温馨的世界,而不公平被认为不是好事,那么在锁的世界中如何呢?
当执行加锁操作时,公平性将由于挂起线程和恢复线程时存在的开销而大大降低性能。在实际的大多数情况中,非公平锁的性能要远高于公平锁的性能。

下图是Map的性能测试,并比较有公平的以及非公平的ReentrantLock包装的HashMap的性能,从图中可以看出,公平性把性能降低了约2个数量级:
在这里插入图片描述

备注ConcurrentHashMap在线程数为4到8之间有一些波动,这个波动属于测量噪声,这种噪声在性能测试中常有,对整体结果不造成实质性影响可不做过度关注。

从上图可以看出来,在激烈竞争下,非公平锁的性能远高于公平锁的性能,其原因是:在恢复一个被挂起的线程 与线程真正开始运行之间存在着严重的延迟。

  • 假设线程A持有一个锁,并且线程B请求这个锁。
  • 由于这个锁已经被线程A持有了,线程B将被放入队列中挂起。
  • 当A释放锁时,B将被唤醒,因此会再次尝试获取锁。
  • 与此同时,正好有个C线程来请求这个锁,那么C线程很有可能在B被完全唤醒之前抢到,使用以及释放这个锁。
  • 等C线程使用完释放后,B线程正好被唤醒,获取此锁并使用。

如此赢得了双赢的局面,线程B获取锁的时间并没有被延迟,C也在B唤醒的空挡中干完了自己的工作,因此最终的吞吐量也得以提高。

那么什么时候使用公平锁呢?
当持有的锁的时间相对较长,或者请求锁的平均时间间隔较长,那么应该使用公平锁。在这种情况下,“插队”带来的吞吐量的提升(当锁处于可用状态时,线程却还处于被唤醒的过程中)则可能不会出现。

ReentrantLock与内置锁

说到锁就不得不提我们最熟悉的内置锁:Sychronized,那么这两种锁又该如何选择呢?
ReentrantLock相比内置锁还通了包括定时的锁等待,可中断的锁等待,公平性,以及实现非块结构的枷锁。其性能上似乎是优于内置锁,其中在Java6略有胜出,在Java5则远远胜出。既然如此,我们为什么不抛弃内置锁,直接选择ReentrantLock呢?
原因在于

  • ReentrantLock的危险性比内置锁要高,如果忘记在finaly块中调用unlock方法,却虽然代码表面上可以正常运行,但却等于埋了一颗定时炸弹,还有可能伤及无辜。
  • 另外,Sychronized还有一个ReentrantLock所没有的优点,就是在线程转储中能给出在哪些调用帧中获得了那些锁,并能够检测和识别发生死锁的线程。在Java6中还提供了给管理和调试接口,锁可以通过该接口进行注册,从而一些相关的加锁信息就能出现在线程转储中,给程序员带来一些帮助。而ReentrantLock的非块状结构特性获取锁的操作不能与特定的栈帧关联起来,而内置锁却可以。
  • 未来更可能会提升Sychronized而不是ReentrantLock的性能。因为Sychronized是JVM内置属性,它能执行一些优化,例如对线程封闭的锁对象的锁消除优化,Java6开始的锁升级的优化。

那么什么时候该选择ReentrantLock呢?
在一些内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具。当需要一些高级功能的时候才应该使用ReentrantLock,比如可定时的,可轮询的与可中断的锁获取操作,公平队列,以及非块状结构的锁。否则还是应该优先使用内置锁Sychronized

---------------你知道的越多,不知道的越多--------------


http://chatgpt.dhexx.cn/article/SX2KRnU1.shtml

相关文章

aqs原理初探以及公平锁和非公平锁实现

深入理解AQS 一,AQS1,ReentrantLock2,CAS3,AbstractQueuedSynchronizer3.1,FairSync3.2,NofairSync3.3,AQS中几个重要的相关参数3.4,Node 一,AQS AbstractQueuedSynchro…

图解ReentrantLock底层公平锁和非公平锁实现原理

💻在面试或者日常开发当中,经常会遇到公平锁和非公平锁的概念。 两者最大的区别如下👇 1️⃣ 公平锁:N个线程去申请锁时,会按照先后顺序进入一个队列当中去排队,依次按照先后顺序获取锁。就像下图描述的上…

ReentrantLock之公平锁和非公平锁详解

ReentrantLock是一个互斥锁,它具有synchronized相同的能力;但相比之下,ReentrantLock扩展性更强,比如实现了公平锁。 下面详细拆解下ReentrantLock的公平锁和非公平锁的实现。 JDK版本:1.8.0_40 公平锁 先看Reentr…

ReentrantLock中公平锁和非公平锁的区别

目录 背景知识 ReentrantLock的组成 概述 公平锁示意图 非公平锁示意图 源码解读 非公平锁 公平锁 代码对比 问题 知识扩展 tryLock方法 参考资料 背景知识 ReentrantLock的组成 首先看下ReentrantLock的组成结构。 公平锁和非公平锁主要是通过内部类FairSync和…

公平锁和非公平锁

Reentrant Re entrant,Re是重复、又、再的意思,entrant是enter的名词或者形容词形式,翻译为进入者或者可进入的,所以Reentrant翻译为可重复进入的、可再次进入的,因此ReentrantLock翻译为重入锁或者再入锁。 公平锁…

阿里面试官:说一下公平锁和非公平锁的区别?

点赞再看,养成习惯,微信搜索【三太子敖丙】关注这个互联网苟且偷生的工具人。 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点、资料以及我的系列文章。 前言 上次我们提到了乐观锁和悲观锁,那我们知道…

Ubuntu 手动安装 JDK8

文章目录 1. 下载2. 解压安装3. 配置环境变量 1. 下载 先去官网下载合适的版本,官网:https://www.oracle.com/java/technologies/downloads/archive/ 通过下载页面获取到下载链接后,可以直接在Ubuntu上使用wget下载,也可以先下载…

centos8安装jdk教程

文章目录 一、安装二、配置环境变量三.验证 一、安装 1、查看JDK软件包列表 yum search java | grep -i --color jdk2、选择版本安装 yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel或者如下命令安装jdk8所有文件 yum install -y java-1.8.0-openjdk*二、配置…

Java - JDK8安装及配置环境变量教程

Java - JDK8安装及配置环境变量教程 一、安装JDK教程 甲骨文官网下载JDK版本:windows64下载地址 下载完成后开始安装JDK:双击打开 点击下一步: 若不需要自定义路径,则安装到默认路径即可(安装的路径需记住&#xff0…

JDK8安装和环境配置

JDK8的安装和环境配置 一、JDK8下载二、安装三、环境配置 一、JDK8下载 官网下载: https://www.oracle.com/java/technologies/downloads/#java8-windows 二、安装 打开安装,一直下一步即可,可以在安装过程中更改安装地址,我放…

Java JDK 8的安装与配置

文章目录 前言1. 安装JDK 8Step1:选择JDK的版本Step2:选择系统平台Step3:下载安装包Step4:开始安装 2. 配置JDK 8Step1:配置“环境变量path” 前言 本教程是在Windows 64位平台上安装JDK 8版本。 1. 安装JDK 8 官网…

JDK8安装与环境配置

前言:在网上看了下JDK的安装与环境配置,发现很多视频以及博客的讲的都很复杂,对初学者很不友好。很多小白看到这些配置步骤都一脸懵,即使一步一步看着操作还是配置失败。这主要是因为很多博主配置了不需要的配置环境,让…

Linux安装JDK8详细图文教程

第一步、获取JDK文件 JDK下载包:直接进入 如果跳转登录页面,注册一个账号登录即可 登录过后文件就下载完成 第二步、上传JDK到服务器 1、创建JDK目录 mkdir -p /developer/env/jdk进入目录 cd /developer/env/jdk2、安装lrzsz(用于远程传…

JDK8安装教程(Windows、Ubuntu)

文章目录 下载JDK8在Windows上安装设置环境变量 在Ubuntu上安装 下载JDK8 Linux版,CSDN下载地址 推荐官网下载(需要注册),能下到Windows和Ubuntu的最新版 在Windows上安装 双击打开下载好的安装包,点击下一步 点击左…

linux系统安装jdk8详细教程

文章目录 前言一、下载jdk8的安装包二、压缩包上传解压1.将下载好的压缩包使用ftp工具上传到服务器2.将压缩包解压到指定目录 三、配置jdk的环境变量四、测试是否安装成功 前言 虚拟机版本:centos7 jdk版本:1.8 一、下载jdk8的安装包 方法1&#xff1a…

jdk8安装教程及环境变量配置

目录 一、JDK下载 二、安装JDK 三、环境变量配置 四、测试环境变量 一、JDK下载 1、JDK下载地址:Java Downloads | Oraclehttps://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 2、选这个位置 3、向下滑动鼠标&#xff0c…

WIN10javaJDK8安装教程

一、下载jdk8文件 下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载步骤: 1、进入网站后往下拉,找到下载界面,选择自己合适的下载。 二、安装 双击运行刚下载好的exe文件…

JDK8安装教程-极其详细

下载安装JDK 前往oracle官网下载JDK 链接:https://www.oracle.com/java/technologies/downloads/#java8-windows下载完成后 打开下载的程序进行安装JDK 这里可以选择你要存放的位置 选择jre安装的路径 继续下一步,等待安装完成 配置环境变量 此电脑…

jdk8安装教程及环境变量部署

一、jdk下载 下载方式: 官网下载 地址:Java Downloads | Oracle网盘下载:链接:https://pan.baidu.com/s/1jjcOsdyaLfAy2N5zp64sew 提取码:tzsj 官网下载: 这是最新版本的可以根据自己的需要选择 选择W…

win10系统安装jdk8全过程

一 下载安装文件 jdk的安装与配置是Java学习的第一步,下面记录一下具体过程。首先根据自己系统下载对应版本。下载地址http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 二 安装 双击exe文件,按照默认设置一步一步…