当前位置: 首页 > news >正文

对ReentrantLock的公平性进行测试

ReentrantLock公平性实现原理

在ReentrantLock类内部定义了一个内部类Sync以及两个实现NonfairSync和FairSync,它们内部定义了锁获取和释放的逻辑,下面我列出了两种同步类的代码,通过观察两个代码的差异就可以看到公平性是如何实现的。
NonfairSync和FairSync的差异如下:
差异1:非公平锁在获取锁时增加一条shortcut尝试快速获取锁
差异2:公平锁在尝试获取锁前需保证当前线程位于AQS队列的头部

  static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L;/*** Performs lock.  Try immediate barge, backing up to normal* acquire on failure.*/final void lock() {if (compareAndSetState(0, 1))     // 差异1:非公平锁在一开始可以直接尝试获取锁,而不需要再经过acquire->tryAcquire->nonfairTryAcquire这样长的路径setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 差异2:非公平锁在获取锁时,不需要判断当前线程是否处在队头if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
}
static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;final void lock() {// 差异1:公平锁不能在一开始直接获取锁,否则可能先于队列中的等待线程获取到锁,破坏了公平性acquire(1);}/*** Fair version of tryAcquire.  Don't grant access unless* recursive call or no waiters or is first.*/protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 差异2:公平锁实现中,线程处于队头才有资格获取锁,保证了公平性if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
}

总结一下,公平性的实现主要通过在获取锁之间增加一句检查实现,具体来说,调用hasQueuedPredecessors方法检查当前线程是否在队头,只有在队头的线程才能获取到锁,这样,如果新来一个线程,在它入队前是不会拿到锁的,从而保证了线程获取锁的顺序 = 线程申请锁的顺序,也就是说实现了公平性。

ReentrantLock公平性测试

在上一节,说到了ReentrantLock的公平性,如果是公平锁,线程获取锁的顺序 = 线程访问锁的顺序,如果是非公平锁,线程获取锁的顺序 ≠ 线程访问锁的顺序,那也就是说,如果使用非公平锁,一个还没有被加入到队列的新线程可能会抢走早已在队列中等待的线程的锁。基于这个思路,我们来写一个程序来验证ReentrantLock的公平性。
具体步骤如下:

  • 主线程获取锁但不释放;
  • 创建若干打印线程(打印字符p)并运行,这些线程不能拿到锁,因而被依次放到队列中等待;
  • 主线程释放锁,同时立即创建几个新打印线程(打印字符s)运行。

假如是公平锁,那么新打印线程必定会入队等待,按序获取锁,那么最终打印的字符s永远不可能出现在字符p之前;但如果是非公平锁,新打印线程有机会与旧打印线程同时竞争锁,那么这时候字符s可能会出现在字符p之前。
最终的程序如下:

import org.junit.jupiter.api.Test;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;import static org.junit.jupiter.api.Assertions.*;class ReentrantLockTest {@Testpublic void test() throws InterruptedException {ReentrantLock lock = new ReentrantLock(true);final int threadNum = 50;// 主线程先获取锁lock.lock();// 将几个线程在锁队列中排队List<Thread> threads = new ArrayList<>();for (int i = 0; i < threadNum; i++) {Thread thread = new Thread(() -> {try {lock.lock();System.out.printf(Thread.currentThread().getName() + " ");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}, "p");thread.start();threads.add(thread);}// 主线程释放锁,再创建几个线程竞争锁Thread.sleep(200);lock.unlock();List<Thread> threads1 = new ArrayList<>();for (int i = 0; i < threadNum * 2; i++) {Thread thread = new Thread(() -> {try {lock.lock();System.out.printf(Thread.currentThread().getName() + " ");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}, "s");thread.start();threads.add(thread);}for (Thread thread : threads) {thread.join();}// 预计successor-number可能输出在number之前}
}

fair为true时输出结果为:

p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s 

fair为false时输出结果为:

p p p p p s p s s p p s p s s s p p p p p s s p p p s p s p p p s p s p p p s p s p p p s p p p s p p p p p p p s p p p s p s p s s p p s p s p p p s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s 

相关文章:

对ReentrantLock的公平性进行测试

ReentrantLock公平性实现原理 在ReentrantLock类内部定义了一个内部类Sync以及两个实现NonfairSync和FairSync&#xff0c;它们内部定义了锁获取和释放的逻辑&#xff0c;下面我列出了两种同步类的代码&#xff0c;通过观察两个代码的差异就可以看到公平性是如何实现的。 Nonf…...

LabVIEW之TDMS文件

在很多场合&#xff0c;早期的LabVIEW版本不得不借助常规的数据库来做一些数据管理工作&#xff0c;但常规数据库对于中高速数据采集显然是不合适的&#xff0c;因为高速数据采集的数据量非常大&#xff0c;用一般的数据库无法满足存储数据的要求。 直到TDM(Technical Data Ma…...

DeepSeek 实现原理探析

DeepSeek 实现原理探析 引言 DeepSeek 是一种基于深度学习的智能搜索技术&#xff0c;它通过结合自然语言处理&#xff08;NLP&#xff09;、信息检索&#xff08;IR&#xff09;和机器学习&#xff08;ML&#xff09;等多领域的技术&#xff0c;旨在提供更加精准、智能的搜索…...

2021 年 9 月青少年软编等考 C 语言五级真题解析

目录 T1. 问题求解思路分析T2. 抓牛思路分析T3. 交易市场思路分析T4. 泳池思路分析T1. 问题求解 给定一个正整数 N N N,求最小的 M M M 满足比 N N N 大且 M M M 与 N N N 的二进制表示中有相同数目的 1 1 1。 举个例子,假如给定 N N N 为 78 78 78,二进制表示为 …...

洛谷网站: P3029 [USACO11NOV] Cow Lineup S 题解

题目传送门&#xff1a; P3029 [USACO11NOV] Cow Lineup S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 前言&#xff1a; 这道题的核心问题是在一条直线上分布着不同品种的牛&#xff0c;要找出一个连续区间&#xff0c;使得这个区间内包含所有不同品种的牛&#xff0c;…...

编程领域的IO模型(BIO,NIO,AIO)

目前对于市面上绝大多数的应用来说&#xff0c;不能实现的业务功能太少了。更多的是对底层细节&#xff0c;性能优化的追求。其中IO就是性能优化中很重要的一环。Redis快&#xff0c;mysql缓冲区存在的意义。都跟IO有着密切关系。IO其实我们都在用&#xff0c;输入输出流这块。…...

DeepSeek和ChatGPT的对比

最近DeepSeek大放异彩&#xff0c;两者之间有什么差异呢&#xff1f;根据了解到的信息&#xff0c;简单做了一个对比。 DeepSeek 和 ChatGPT 是两种不同的自然语言处理&#xff08;NLP&#xff09;模型架构&#xff0c;尽管它们都基于 Transformer 架构&#xff0c;但在设计目标…...

Pyqt 的QTableWidget组件

QTableWidget 是 PyQt6 中的一个表格控件&#xff0c;用于显示和编辑二维表格数据。它继承自 QTableView&#xff0c;提供了更简单的方式来处理表格数据&#xff0c;适合用于需要展示结构化数据的场景。 1. 常用方法 1.1 构造函数 QTableWidget(parent: QWidget None)&#x…...

4. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--什么是微服务--微服务设计原则与最佳实践

相比传统的单体应用&#xff0c;微服务架构通过将大型系统拆分成多个独立的小服务&#xff0c;不仅提升了系统的灵活性和扩展性&#xff0c;也带来了许多设计和运维上的挑战。如何在设计和实现微服务的过程中遵循一系列原则和最佳实践&#xff0c;从而构建一个稳定、高效、易维…...

网络安全威胁框架与入侵分析模型概述

引言 “网络安全攻防的本质是人与人之间的对抗&#xff0c;每一次入侵背后都有一个实体&#xff08;个人或组织&#xff09;”。这一经典观点概括了网络攻防的深层本质。无论是APT&#xff08;高级持续性威胁&#xff09;攻击、零日漏洞利用&#xff0c;还是简单的钓鱼攻击&am…...

树和二叉树_7

树和二叉树_7 一、leetcode-102二、题解1.引库2.代码 一、leetcode-102 二叉树的层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 样例输入&#xff1a;root [3,9,20,null,nu…...

不同标签页、iframe或者worker之间的广播通信——BroadcastChannel

BroadcastChannel是一个现代浏览器提供的 API&#xff0c;用于在同一浏览器的不同浏览上下文&#xff08;如不同的标签页、iframe 或者 worker&#xff09;之间进行消息传递。它允许你创建一个广播频道&#xff0c;通过该频道可以在不同的浏览上下文之间发送和接收消息。 Broa…...

开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具

开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具 背景与研究目的 在快速发展的软件开发领域,代码辅助工具已成为提高开发效率和质量的关键。然而,商业付费工具如通义灵码和腾讯AI代码助手,尽管功能强大,但其高昂的成本和许可证限制,使得许多企业寻求更具吸…...

AUTOSAR汽车电子嵌入式编程精讲300篇-基于FPGA的CAN FD汽车总线数据交互系统设计

目录 前言 汽车总线以及发展趋势 汽车总线技术 汽车总线发展趋势 CAN FD总线国内外研究现状 2 系统方案及CAN FD协议分析 2.1系统控制方案设计 2.2 CAN FD总线帧结构分析 2.2.1数据帧分析 2.2.2远程帧分析 2.2.3过载帧分析 2.2.4错误帧分析 2.2.5帧间隔分析 2.3位…...

STC51案例操作

案例 1&#xff1a;LED 闪烁 功能描述&#xff1a;通过操作 P1 口寄存器&#xff0c;让连接在 P1.0 引脚的 LED 以一定间隔闪烁。 #include <reg51.h>// 延时函数 void delay(unsigned int time) {unsigned int i, j;for (i 0; i < time; i)for (j 0; j < 123; …...

多光谱技术在华为手机上的应用发展历史

2018 年&#xff0c;华为 P20 系列首次搭载 5 通道色温传感器&#xff0c;可帮助手机在不同光照条件下保持画面色彩一致性。 2020 年&#xff0c;华为 P40 系列搭载 8 通道多光谱色温传感器&#xff08;实际为 11 通道&#xff0c;当时只用 8 个通道检测可见光&#xff09;&am…...

C语言:函数栈帧的创建和销毁

目录 1.什么是函数栈帧2.理解函数栈帧能解决什么问题3.函数栈帧的创建和销毁的过程解析3.1 什么是栈3.2 认识相关寄存器和汇编指令3.3 解析函数栈帧的创建和销毁过程3.3.1 准备环境3.3.2 函数的调用堆栈3.3.3 转到反汇编3.3.4 函数栈帧的创建和销毁 1.什么是函数栈帧 在写C语言…...

NLP_[2]_文本预处理-文本数据分析

文章目录 4 文本数据分析1 文件数据分析介绍2 数据集说明3 获取标签数量分布4 获取句子长度分布5 获取正负样本长度散点分布6 获取不同词汇总数统计7 获取训练集高频形容词词云8 小结 4 文本数据分析 学习目标 了解文本数据分析的作用.掌握常用的几种文本数据分析方法. 1 文…...

【工具篇】深度揭秘 Midjourney:开启 AI 图像创作新时代

家人们,今天咱必须好好唠唠 Midjourney 这个在 AI 图像生成领域超火的工具!现在 AI 技术发展得那叫一个快,各种工具层出不穷,Midjourney 绝对是其中的明星产品。不管你是专业的设计师、插画师,还是像咱这种对艺术创作有点小兴趣的小白,Midjourney 都能给你带来超多惊喜,…...

从O(k*n)到O(1):如何用哈希表终结多层if判断的性能困局

【前言】   本文将以哈希表重构实战为核心&#xff0c;完整展示如何将传统条件匹配逻辑(上千层if-else判断)转化为O(1)的哈希表高效实现。通过指纹验证场景的代码级解剖&#xff0c;您将深入理解&#xff1a;   1.哈希函数设计如何规避冲突陷阱   2.链式寻址法的工程实现…...

终极音乐解锁指南:3步免费解锁任何加密音乐文件

终极音乐解锁指南&#xff1a;3步免费解锁任何加密音乐文件 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地址: https://git…...

Linux 系统运行速度慢有哪些排查方法?

Linux 系统变慢通常是资源供需失衡导致的&#xff0c;建议按 CPU、内存、磁盘 I/O、网络的顺序依次排查&#xff0c;优先使用 top、free、iostat 等基础命令定位瓶颈。 先说结论&#xff1a;系统卡顿本质是核心资源被过度占用&#xff0c;需先定位具体瓶颈资源&#xff0c;再针…...

NotebookLM笔记生产力跃迁(仅限前500名早鸟用户的动态模板库已开放)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;NotebookLM笔记生产力跃迁&#xff08;仅限前500名早鸟用户的动态模板库已开放&#xff09; NotebookLM 正式引入基于语义理解的「上下文感知模板引擎」&#xff0c;早鸟用户可通过专属入口启用动态模板…...

避开这些坑!用Unity做Flappy Bird时,我遇到的5个典型问题及解决方案

避开这些坑&#xff01;用Unity做Flappy Bird时&#xff0c;我遇到的5个典型问题及解决方案 第一次用Unity复现Flappy Bird这类经典小游戏时&#xff0c;本以为跟着教程一步步操作就能顺利完成&#xff0c;结果从素材导入到最终发布的每个环节都暗藏玄机。特别是当教程只展示&q…...

独立开发者工具箱:模块化架构与全栈实践指南

1. 项目概述&#xff1a;一个独立开发者的工具箱 如果你是一个独立开发者&#xff0c;或者正在尝试构建自己的数字产品&#xff0c;那么你一定经历过这样的时刻&#xff1a;一个想法在脑海中成型&#xff0c;你迫不及待地想把它变成现实&#xff0c;但当你打开编辑器&#xff0…...

HFSS新手避坑指南:手把手教你设置Floquet Port和主从边界(附矩形波导实例)

HFSS阵列仿真实战&#xff1a;从Floquet Port到主从边界的精准设置 第一次打开HFSS准备仿真周期性结构时&#xff0c;那种既兴奋又忐忑的心情我至今记忆犹新。作为计算电磁学领域的黄金标准工具&#xff0c;HFSS在阵列天线、频率选择表面等周期性结构分析中展现出无可替代的价…...

汽车软件平台演进:从AUTOSAR到Hypervisor,如何重塑开发与商业模式

1. 汽车软件平台现状&#xff1a;从“硬骨头”到“乐高积木”的演进干了十几年汽车电子&#xff0c;我亲眼看着车里的代码从几万行膨胀到上亿行。十年前&#xff0c;我们还在为某个ECU&#xff08;电子控制单元&#xff09;里塞进一个简单的网络协议栈而通宵调试&#xff1b;现…...

手机号查QQ号终极指南:3分钟掌握Python逆向查询技巧

手机号查QQ号终极指南&#xff1a;3分钟掌握Python逆向查询技巧 【免费下载链接】phone2qq 项目地址: https://gitcode.com/gh_mirrors/ph/phone2qq 你是否曾需要快速验证手机号与QQ号的绑定关系&#xff1f;手机号查QQ号工具是一个简单高效的Python开源项目&#xff0…...

为什么 Promise 比 setTimeout 先执行?——JavaScript 事件循环与异步顺序完全指南

为什么 Promise 比 setTimeout 先执行&#xff1f;——JavaScript 事件循环与异步顺序完全指南 这是 JavaScript 异步中最经典也最容易困惑的问题之一。核心答案是&#xff1a; Promise 的回调属于 Microtask&#xff08;微任务&#xff09;&#xff0c;setTimeout 属于 Macro…...

如何在Windows上快速安装iPhone网络共享驱动:3分钟终极解决方案

如何在Windows上快速安装iPhone网络共享驱动&#xff1a;3分钟终极解决方案 【免费下载链接】Apple-Mobile-Drivers-Installer Powershell script to easily install Apple USB and Mobile Device Ethernet (USB Tethering) drivers on Windows! 项目地址: https://gitcode.c…...