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

Java多线程:ReentrantLock中的方法

公平锁与非公平锁

ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁,公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的,而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,先来的未必就一定能先得到锁,从这个角度讲,synchronized其实就是一种非公平锁。非公平锁的方式可能造成某些线程一直拿不到锁,自然是非公平的了。看一下例子,new ReentrantLock的时候有一个单一参数的构造函数表示构造的是一个公平锁还是非公平锁,传入true就可以了:

public class ThreadDomain42 {private Lock lock = new ReentrantLock(true);public void testMethod() {try {lock.lock();System.out.println("ThreadName" + Thread.currentThread().getName() + "获得锁");} finally {lock.unlock();}}}public static void main(String[] args) throws Exception {final ThreadDomain42 td = new ThreadDomain42();Runnable runnable = new Runnable() {public void run() {System.out.println("◆线程" + Thread.currentThread().getName() + "运行了");td.testMethod();}};Thread[] threads = new Thread[5];for (int i = 0; i < 5; i++)threads[i] = new Thread(runnable);for (int i = 0; i < 5; i++)threads[i].start();}

看一下运行结果:

◆线程Thread-0运行了

◆线程Thread-3运行了

ThreadNameThread-0获得锁

◆线程Thread-2运行了

◆线程Thread-1运行了

ThreadNameThread-3获得锁

◆线程Thread-4运行了

ThreadNameThread-2获得锁

ThreadNameThread-1获得锁

ThreadNameThread-4获得锁

我们的代码很简单,一执行run()方法的第一步就是尝试获得锁。看到结果里面获得锁的顺序和线程启动顺序是一致的,这就是公平锁。对比一下,如果是非公平锁运行结果是怎么样的,在new ReentrantLock的时候传入false:

◆线程Thread-1运行了

◆线程Thread-2运行了

◆线程Thread-0运行了

ThreadNameThread-1获得锁

ThreadNameThread-2获得锁

◆线程Thread-3运行了

◆线程Thread-4运行了

ThreadNameThread-3获得锁

ThreadNameThread-0获得锁

ThreadNameThread-4获得锁

线程启动顺序是1 2 0 3 4,获得锁的顺序却是1 2 3 0 4,这就是非公平锁,它不保证先排队尝试去获取锁的线程一定能先拿到锁

getHoldCount()

getHoldCount()方法返回的是当前线程调用lock()的次数,看一下例子:

public class ThreadDomain43 {private ReentrantLock lock = new ReentrantLock();public void testMethod1() {try {lock.lock();System.out.println("testMethod1 getHoldCount = " + lock.getHoldCount());testMethod2();} finally {lock.unlock();}}public void testMethod2() {try {lock.lock();System.out.println("testMethod2 getHoldCount = " + lock.getHoldCount());} finally {lock.unlock();}}}public static void main(String[] args) {ThreadDomain43 td = new ThreadDomain43();td.testMethod1();}

看一下运行结果:

testMethod1 getHoldCount = 1

testMethod2 getHoldCount = 2

ReentrantLock和synchronized一样,锁都是可重入的,同一线程的同一个ReentrantLock的lock()方法被调用了多少次,getHoldCount()方法就返回多少

getQueueLength()和isFair()

getQueueLength()方法用于获取正等待获取此锁定的线程估计数。注意"估计"两个字,因为此方法遍历内部数据结构的同时,线程的数据可能动态变化

isFair()用来获取此锁是否公平锁

看一下例子:

public class ThreadDomain44 {public ReentrantLock lock = new ReentrantLock();public void testMethod() {try {lock.lock();System.out.println("ThreadName = " + Thread.currentThread().getName() + "进入方法!");System.out.println("是否公平锁?" + lock.isFair());Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}public static void main(String[] args) throws InterruptedException {final ThreadDomain44 td = new ThreadDomain44();Runnable runnable = new Runnable() {public void run() {td.testMethod();}};Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++)threads[i] = new Thread(runnable);for (int i = 0; i < 10; i++)threads[i].start();Thread.sleep(2000);System.out.println("有" + td.lock.getQueueLength() + "个线程正在等待!");}

看一下运行结果:

ThreadName = Thread-0进入方法!

是否公平锁?false

有9个线程正在等待!

ReentrantLock默认的是非公平锁,因此是否公平锁打印的是false。启动了10个线程,只有1个线程lock()了,其余9个等待,都符合预期。

hasQueuedThread()和hasQueuedThreads()

hasQueuedThread(Thread thread)用来查询指定的线程是否正在等待获取指定的对象监视器

hasQueuedThreads()用于查询是否有线程正在等待获取指定的对象监视器

看一下例子,换一个写法,ReentrantLock既然是一个类,就有类的特性,所以这次用继承ReentrantLock的写法,这也是很常见的:

public class ThreadDomain45 extends ReentrantLock {public void waitMethod() {try {lock();Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();} finally {unlock();}}}public static void main(String[] args) throws InterruptedException {final ThreadDomain45 td = new ThreadDomain45();Runnable runnable = new Runnable() {public void run() {td.waitMethod();}};Thread t0 = new Thread(runnable);t0.start();Thread.sleep(500);Thread t1 = new Thread(runnable);t1.start();Thread.sleep(500);Thread t2 = new Thread(runnable);t2.start();Thread.sleep(500);System.out.println("t0 is waiting?" + td.hasQueuedThread(t0));System.out.println("t1 is waiting?" + td.hasQueuedThread(t1));System.out.println("t2 is waiting?" + td.hasQueuedThread(t2));System.out.println("is any thread waiting?" + td.hasQueuedThreads());}

这里加了几个Thread.sleep(500)保证线程按顺序启动(其实不按顺序启动也关系不大),看一下运行结果:

t0 is waiting?false

t1 is waiting?true

t2 is waiting?true

is any thread waiting?true

由于t0先启动获得了锁,因此不等待,返回false,另外两个线程则要等待获取t0的锁,因此返回的是true,而此ReentrantLock中有线程在等待,所以hasQueuedThreads()返回的是true

isHeldByCurrentThread()和isLocked()

isHeldByCurrentThread()表示此对象监视器是否由当前线程保持

isLocked()表示此对象监视器是否由任意线程保持

看一下例子:

public class ThreadDomain46 extends ReentrantLock {public void testMethod() {try {lock();System.out.println(Thread.currentThread().getName() + "线程持有了锁!");System.out.println(Thread.currentThread().getName() + "线程是否持有锁?" +isHeldByCurrentThread());System.out.println("是否任意线程持有了锁?" + isLocked());Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();} finally {unlock();}}public void testHoldLock() {System.out.println(Thread.currentThread().getName() + "线程是否持有锁?" +isHeldByCurrentThread());System.out.println("是否任意线程持有了锁?" + isLocked());}}public static void main(String[] args) {final ThreadDomain46 td = new ThreadDomain46();Runnable runnable0 = new Runnable() {public void run() {td.testMethod();}};Runnable runnable1 = new Runnable() {public void run() {td.testHoldLock();}};Thread t0 = new Thread(runnable0);Thread t1 = new Thread(runnable1);t0.start();t1.start();}

看一下运行结果:

Thread-0线程持有了锁!

Thread-1线程是否持有锁?false

Thread-0线程是否持有锁?true

是否任意线程持有了锁?true

是否任意线程持有了锁?true

这个应该很好理解,当前持有锁的是Thread-0线程,所以对于Thread-1来说自然不持有锁。

tryLock()和tryLock(long timeout, TimeUnit unit)

tryLock()方法的作用是,在调用try()方法的时候,如果锁没有被另外一个线程持有,那么就返回true,否则返回false

tryLock(long timeout, TimeUnit unit)是tryLock()另一个重要的重载方法,表示如果在指定等待时间内获得了锁,则返回true,否则返回false

注意一下,tryLock()只探测锁是否,并没有lock()的功能,要获取锁,还得调用lock()方法,看一下tryLock()的例子:

 public class ThreadDomain47 extends ReentrantLock {public void waitMethod() {if (tryLock())System.out.println(Thread.currentThread().getName() + "获得了锁");elseSystem.out.println(Thread.currentThread().getName() + "没有获得锁");}}public static void main(String[] args) {final ThreadDomain47 td = new ThreadDomain47();Runnable runnable = new Runnable() {public void run() {td.waitMethod();}};Thread t0 = new Thread(runnable);Thread t1 = new Thread(runnable);t0.start();t1.start();}

看一下运行结果:

Thread-0获得了锁

Thread-1没有获得锁

第一个线程获得了锁返回true,第二个线程自然返回的false。由于有了tryLock()这种机制,如果一个线程长时间在synchronzied代码/synchronized代码块之中,别的线程不得不长时间无限等待的情况将可以被避免。

ReentrantLock中的其他方法

篇幅原因,ReentrantLock中还有很多没有被列举到的方法就不写了,看一下它们的作用:

1、getWaitQueueLength(Condition condition)

类似getQueueLength(),不过此方法的前提是condition。比如5个线程,每个线程都执行了同一个await()的await()方法,那么方法调用的返回值是5,因为5个线程都在等待获得锁

2、hasWaiters(Condition condition)

查询是否有线程正在等待与此锁有关的condition条件。比如5个线程,每个线程都执行了同一个condition的await()方法,那么方法调用的返回值是true,因为它们都在等待condition

3、lockInterruptibly()

如果当前线程未被中断,则获取锁

4、getWaitingThreads(Condition condition)

返回一个collection,它包含可能正在等待与此锁相关给定条件的那些线程,因为构造结果的时候实际线程可能动态变化,因此返回的collection只是尽力的估计值

相关文章:

Java多线程:ReentrantLock中的方法

公平锁与非公平锁 ReentrantLock有一个很大的特点&#xff0c;就是可以指定锁是公平锁还是非公平锁&#xff0c;公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的&#xff0c;而非公平锁就是一种获取锁的抢占机制&#xff0c;是随机获得锁的&#xff0c;先来的未必就一…...

RabbitMQ初识快速入门

RabbitMQ初识&快速入门1.初识MQ1.1.同步和异步通讯1.1.1.同步通讯1.1.2.异步通讯1.2.技术对比&#xff1a;2.快速入门2.1.安装RabbitMQ2.1.1 下载镜像2.1.2 安装MQ2.2.RabbitMQ消息模型2.3.导入Demo工程2.4.入门案例2.4.1.publisher实现2.4.2.consumer实现2.5.总结1.初识MQ…...

由浅入深了解HashMap源码

由经典面试题引入&#xff0c;讲解一下HashMap的底层数据结构&#xff1f;这个面试题你当然可以只答&#xff0c;HashMap底层的数据结构是由&#xff08;数组链表红黑树&#xff09;实现的&#xff0c;但是显然面试官不太满意这个答案&#xff0c;毕竟这里有一个坑需要你去填&a…...

P5318 【深基18.例3】查找文献

题目描述 小K 喜欢翻看洛谷博客获取知识。每篇文章可能会有若干个&#xff08;也有可能没有&#xff09;参考文献的链接指向别的博客文章。小K 求知欲旺盛&#xff0c;如果他看了某篇文章&#xff0c;那么他一定会去看这篇文章的参考文献&#xff08;如果他之前已经看过这篇参考…...

Error caught was: No module named ‘triton‘

虽然报错但是不影响程序运行&#xff1a; A matching Triton is not available, some optimizations will not be enabled. Error caught was: No module named triton解决&#xff1a; pip install -i https://pypi.tuna.tsinghua.edu.cn/simple triton2.0.0.dev20221120...

Ruby设计-开发日志

Log 1 产品 Product 1.1 创建 Product 创建名为 project 的 rails 应用 rails new project创建 Product 模型 rails generate scaffold Product title:string description:text image_url:string price:decimal这会生成一个 migration &#xff0c;我们需要进一步修改这个…...

SpringBoot 调用外部接口的三种方式

方式一&#xff1a;使用原始httpClient请求 /** description get方式获取入参&#xff0c;插入数据并发起流程* params documentId* return String*/ RequestMapping("/submit/{documentId}") public String submit1(PathVariable String documentId) throws ParseE…...

C 中的结构体

C 中的结构体 C 数组允许定义可存储相同类型数据项的变量&#xff0c;结构是 C 编程中另一种用户自定义的可用的数据类型&#xff0c;它允许您存储不同类型的数据项。 结构体中的数据成员可以是基本数据类型&#xff08;如 int、float、char 等&#xff09;&#xff0c;也可以…...

nodejs安装教程

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时&#xff0c;可以用于在服务器端运行 JavaScript 代码。以下是 Node.js 的安装教程&#xff1a; 步骤 1&#xff1a;下载 Node.js 访问 Node.js 的官方网站 https://nodejs.org/&#xff0c;进入官方下载页面。 在下载页…...

【华为OD机试】1029 - 整数与IP地址间的转换

文章目录一、题目&#x1f538;题目描述&#x1f538;输入输出&#x1f538;样例1二、代码参考作者&#xff1a;KJ.JK&#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x…...

【FPGA实验1】FPGA点灯工程师养成记

对于FPGA几个与LED相关的实验&#xff08;包括按键点灯、流水灯、呼吸灯等&#xff09;的记录&#xff0c;方便日后查看。这世界上就又多了一个FPGA点灯工程师了&#x1f60f; 成为一个FPGA点灯工程师分三步&#xff1a;一、按键点灯1、按键点灯程序2、硬件实现二、流水灯1、流…...

操作系统论文导读(三):Stack-based scheduling of realtime processes基于堆栈的实时进程调度

目录 一、论文核心思想&#xff1a; 二、基本的相关条件 作业运行的条件&#xff1a; 作业抢占其他作业的条件&#xff1a; 三、基本的相关定义 四、基本的相关调度 五、基本的相关调度 六、堆栈资源共享 七、与PCP的比较 一、论文核心思想&#xff1a; -引入了一个抢占优…...

音频延时测试方法与实现

音频延时测试方法有以下几种 1、使用专业的测试设备&#xff0c;通过专业的音频测试仪器可以准确测量音频延时&#xff0c;如常见声学分析仪、信号发生器、声卡Smaart&#xff08;介绍测试延时方法链接&#xff1a;https://blog.csdn.net/weixin_48408892/article/details/1273…...

在 Python 中管理机密的四种方法

我们生活在一个应用程序用于做任何事情的世界&#xff0c;无论是股票交易还是预订沙龙&#xff0c;但在幕后&#xff0c;连接是使用秘密完成的。必须适当管理机密&#xff0c;例如数据库密码、API 密钥、令牌等&#xff0c;以避免任何泄露。 管理机密的需求对任何组织都至关重…...

全国青少年信息素养大赛Python编程挑战赛初赛试题说明

Python 编程挑战赛初赛采用线上考试比赛形式,分为小学组和初中组。不同组别的考核重难点略有不同,考核内容主要是 Python 基础知识,共 30 题,均为单选题,具体考核如下: 小学组考核内容主要是 Python 基础知识,包括输入输出,变量,条件结构,计次循环和无限循环,海龟库…...

无需魔法打开即用的 AI 工具集锦

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;蚂蚁集团高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐…...

如何进行SEO站内优化,让你的网站更易被搜索引擎收录

我们了解了 SEO 的流程&#xff0c;知道了哪些元素对 SEO 的效果会产生关键影响&#xff0c;接下来&#xff0c;我们就该正式开始动手&#xff0c;打造一个让搜索引擎“爱不释手”的网站。 为了方便理解与记忆&#xff0c;我们将网站划分为几个模块&#xff0c;告诉你优化网站…...

组件内部watch后切换数据报错Error in callback for watcher “xxxx“

报错信息&#xff1a; 报错代码&#xff1a; 百度了一下是因为这里写了箭头函数&#xff0c;导致this指向为父级作用域上下文&#xff0c;不是vue实例导致 修改为&#xff1a; progressData: {handler: function(newValue, oldValue) {this.setChartData(newValue)},deep: …...

VMware ESXi 7.0 U3l macOS Unlocker OEM BIOS (标准版和厂商定制版)

VMware ESXi 7.0 U3l macOS Unlocker & OEM BIOS (标准版和厂商定制版) 提供标准版和 Dell (戴尔)、HPE (慧与)、Lenovo (联想)、Inspur (浪潮)、Cisco (思科) 定制版镜像 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-7-u3-oem/&#xff0c;查看最新版…...

华为阿里版ChatGPT横空出世,谁的成效更好呢?

“你训练的大模型涌现了吗&#xff1f;”“还没有。好难受。”一时间成为了最近AI赛道玩家的一个爆热梗。 不管承不承认&#xff0c;相信每个玩家都不愿意输掉这场激烈的竞争。自百度成为国内“第一个吃螃蟹的人”后&#xff0c;又有两大中国科技巨头做好了准备——华为和阿里…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...