【Java 基础篇】Java Condition 接口详解

Java 提供了一种更灵活和高级的线程协作机制,通过 Condition 接口的使用,你可以更精细地控制线程的等待和唤醒,实现更复杂的线程同步和通信。本文将详细介绍 Java 的 Condition 接口,包括它的基本概念、常见用法以及注意事项。
什么是 Condition 接口?
在 Java 多线程编程中,通常使用 wait() 和 notify() 方法来实现线程之间的等待和唤醒操作。但这两个方法有一些局限性,例如,只能在 synchronized 块内调用,而且每个对象只有一个等待队列。Condition 接口的引入弥补了这些不足,它提供了更灵活的线程协作方式。
Condition 接口是 Java 核心库中 java.util.concurrent.locks 包下的一部分,它通常与 ReentrantLock 一起使用。ReentrantLock 是一种可重入锁,与传统的 synchronized 关键字相比,提供了更多的控制和功能。通过 Condition 接口,你可以为每个 ReentrantLock 创建多个条件(Condition),每个条件可以控制一组线程的等待和唤醒。
Condition 接口的主要方法
Condition 接口定义了一些重要的方法,用于线程的等待和唤醒:
await():使当前线程等待,并释放锁,直到其他线程调用相同条件上的signal()或signalAll()方法来唤醒它。awaitUninterruptibly():与await()类似,但不响应中断。signal():唤醒一个在该条件上等待的线程。如果有多个线程在等待,只会唤醒其中一个,具体唤醒哪个线程不确定。signalAll():唤醒所有在该条件上等待的线程。
Condition 的基本用法
创建 Condition
要使用 Condition 接口,首先需要创建一个与 ReentrantLock 关联的条件对象。通常,一个 ReentrantLock 对象可以创建多个条件对象,用于不同的线程协作。
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
等待和唤醒线程
在使用 Condition 进行线程协作时,通常遵循以下模式:
等待线程
lock.lock(); // 获取锁
try {while (条件不满足) {condition.await(); // 释放锁,并等待条件满足}// 执行线程任务
} finally {lock.unlock(); // 释放锁
}
唤醒线程
lock.lock(); // 获取锁
try {// 修改条件,使等待线程可以继续执行condition.signal(); // 唤醒一个等待线程// 或者使用 condition.signalAll() 唤醒所有等待线程
} finally {lock.unlock(); // 释放锁
}
示例:生产者和消费者问题
让我们通过一个简单的生产者和消费者问题来演示 Condition 的使用。在这个问题中,有一个有界缓冲区,生产者线程将数据放入缓冲区,而消费者线程将数据从缓冲区取出。
首先,我们创建一个有界缓冲区的类:
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class BoundedBuffer<T> {private Queue<T> buffer = new LinkedList<>();private int capacity;private Lock lock = new ReentrantLock();private Condition notFull = lock.newCondition();private Condition notEmpty = lock.newCondition();public BoundedBuffer(int capacity) {this.capacity = capacity;}public void put(T item) throws InterruptedException {lock.lock();try {while (buffer.size() == capacity) {notFull.await();}buffer.offer(item);notEmpty.signal();} finally {lock.unlock();}}public T take() throws InterruptedException {lock.lock();try {while (buffer.isEmpty()) {notEmpty.await();}T item = buffer.poll();notFull.signal();return item;} finally {lock.unlock();}}
}
在这个示例中,我们使用了 ReentrantLock 来保护缓冲区的操作,并分别创建了两个条件 notFull 和 notEmpty,用于控制缓冲区的状态。
接下来,我们可以创建生产者和消费者线程,它们分别向缓冲区放入数据和取出数据:
public class ProducerConsumerExample {public static void main(String[] args) {BoundedBuffer<Integer> buffer = new BoundedBuffer<>(10);Thread producerThread = new Thread(() -> {try {for (int i = 0; i < 100; i++) {buffer.put(i);System.out.println("Produced: " + i);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});Thread consumerThread = new Thread(() -> {try {for (int i = 0; i < 100; i++) {int item = buffer.take();System.out.println("Consumed: " + item);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producerThread.start();consumerThread.start();}
}
在这个示例中,生产者线程不断地向缓冲区放入数据,而消费者线程不断地从缓冲区取出数据,它们通过 await() 和 signal() 方法进行线程协作。
注意事项
在使用 Condition 接口时,需要注意以下几点:
-
必须在获取锁之后才能调用
await()、signal()和signalAll()方法,否则会抛出IllegalMonitorStateException异常。 -
调用
await()方法后,当前线程将释放锁,允许其他线程获取锁并执行。当线程被唤醒后,它将重新尝试获取锁,然后从await()方法返回。 -
signal()方法只能唤醒一个等待线程,如果有多个线程在等待,具体唤醒哪一个是不确定的。如果需要唤醒所有等待线程,可以使用signalAll()方法。 -
在等待时,通常需要将
await()方法包装在一个循环中,以防止虚假唤醒。 -
使用
Condition接口时,要特别小心死锁和竞态条件等多线程问题,确保线程协作的正确性和安全性。
总结
Condition 接口提供了一种更灵活和高级的线程协作机制,可以用于实现复杂的线程同步和通信。通过创建多个条件对象,你可以更精细地控制线程的等待和唤醒。但在使用时需要小心处理锁和条件的关系,以确保线程协作的正确性和可靠性。希望本文对你理解和应用 Condition 接口有所帮助,提高多线程编程的技能。
相关文章:
【Java 基础篇】Java Condition 接口详解
Java 提供了一种更灵活和高级的线程协作机制,通过 Condition 接口的使用,你可以更精细地控制线程的等待和唤醒,实现更复杂的线程同步和通信。本文将详细介绍 Java 的 Condition 接口,包括它的基本概念、常见用法以及注意事项。 什…...
.360勒索病毒和.halo勒索病毒数据恢复|金蝶、用友、ERP等数据恢复
导言: 随着数字化时代的持续发展,网络安全威胁也变得前所未有地复杂和难以应对。在这个充满挑战的网络环境中,勒索病毒已经成为了一种极为危险和破坏性的威胁。最近引起广泛关注的是.360勒索病毒,一种可怕的恶意软件,…...
计算机毕业设计 基于SpringBoot餐厅点餐系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...
天空飞鸟 数据集
今天要介绍的数据集则是天空飞鸟 数据集: 数据集名称:天空飞鸟 数据集 数据集格式:Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件,仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数):以文件包含图片…...
集成学习-树模型
可以分为三部分学习树模型: 基本树(包括 ID3、C4.5、CART).Random Forest、Adaboost、GBDTXgboost 和 LightGBM。基本树 选择特征的准则 ID3:信息增益max C4.5:信息增益比max CART:基尼指数min 优缺点 ID3 核心思想是奥卡姆剃刀(决策树小优于大) 缺点: ID3 没…...
代码随想录算法训练营第一天(C)| 704. 二分查找 27. 移除元素
文章目录 前言一、704. 二分查找二、27. 移除元素三、34. 在排序数组中查找元素的第一个和最后一个位置总结 前言 这次是C; 代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素_愚者__的博客-CSDN博客 (java) 一、704. 二分查找 的优…...
重构优化第三方查询接口返回大数据量的分页问题
# 问题描述 用户线上查询其上网流量详单数据加载慢,且有时候数据没有响应全~ 1、经排除是调用第三方数据量达10w条响应会超时,数据没正常返回 2、现有线上缓存分页也是加载慢数据不能正常展示 3、第三方接口返回类似报文jsonj&#…...
Cento7 Docker安装Zabbix,定制自定义模板
1.先安装docker环境 yum -y install yum-utils device-mapper-persistent-data lvm2#导入docker安装库 yum-config-manager \--add-repo \https://download.docker.com/linux/centos/docker-ce.repo #按指定版本安装好docker yum install docker-ce-20.10.5 docker-ce-cli-20…...
网络防御--防火墙
拓扑 Cloud 1 作为电脑与ENSP的桥梁 防火墙配置 登录防火墙 配置IP地址及安全区域 添加地址对象 配置策略 1、内网可以访问服务器 结果 2、内网可以访问公网 结果 配置NAT策略 结果...
淘宝商品详情数据采集
淘宝商品详情数据采集的方法如下: 确定采集目标:明确要采集的商品信息,如商品标题、价格、销量、评论、图片等。选择采集工具:可以选择Scrapy框架、Java的WebMagic框架等。编写爬虫程序:进入目标文件夹,输…...
mac安装virtualenv和virtualenvwrapper
1.安装(推荐用sudo安装,直接pip3安装会有坑) sudo pip3 install virtualenv sudo pip3 install virtualenvwrapper 2.查看python virtualenvwrapper.sh 位置 # 查看python默认解释器 which python3 # 查看virtualenvwrapper.sh which virtualenvwrapper.sh 3.打…...
利用PCA科学确定各个指标的权重系数
背景参考: 1、提取主成分 对样本进行PCA分析,查看不同变量贡献率,确定主要的指标。我们可以通过下列代码获取需要的所有数据: import numpy as np from sklearn.decomposition import PCA# 创建一个数据 np.random.seed(0) data = np.random.random((100,5)) y = np.ra…...
代码随想录 -- day55 --392.判断子序列 、115.不同的子序列
392.判断子序列 dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。 if (s[i - 1] t[j - 1]) t中找到了一个字符在s中也出现了if (s[i - 1] ! t[j - 1]) 相当于t要删除元素,继续匹配 if (s…...
mysql5升级到mysql8的血泪教训
核心问题1:下载中断这个包就会有问题,下载中断的话一定要重新下载 核心问题2:低版本向高版本迁移 无法整库备份 只能单库备份 1.数据备份 我这里备份了全库,所以后面数据没恢复回来,把DDL语句拆出来了单独建表 mysqldump -u root -p --al…...
Unity 开发人员转CGE(castle Game engine)城堡游戏引擎指导手册
Unity 开发人员的城堡游戏引擎概述 一、简介2. Unity相当于什么GameObject?3. 如何设计一个由多种资产、生物等组成的关卡?4. 在哪里放置特定角色的代码(例如生物、物品)?Unity 中“向 GameObject 添加 MonoBehaviour”…...
卷运维不如卷网络安全
最近发现很多从事运维的选择了辞职,重新规划自己的职业发展方向。运维工程师这个岗位在IT行业里面确实是处于最底层的,不管什么环节出现问题,基本都是运维背锅。背锅也就罢了,薪资水平也比不上别的岗位。 一般运维的薪资水平大多数…...
Digger PRO - Voxel enhanced terrains
资源链接在文末 Digger PRO 是一个简单但强大的工具,可以直接从 Unity 编辑器或游戏中创建天然洞穴和悬岩。会让你感觉自己手中握有一个体素地形,且毫无瑕疵。它实际上保持着最新、最快且可靠的 Unity 地形系统,并在你需要的地方无缝创建洞穴/悬岩峭壁网格。Digger 内…...
文字处理工具 word 2019 mac中文版改进功能
Microsoft Word 2019 是微软公司的文字处理软件,是 office 2019 套件中的一部分。它是一个功能强大、易于使用的工具,可以帮助用户创建各种类型的文档,包括信函、简历、报告、手册等。 Word 2019 提供了许多功能和改进,包括更好的…...
LeetCode 54. 螺旋矩阵
题目链接 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 题目解析 1、求出当前矩阵左上角的元素和右下角的元素。 2、根据这两个元素来确定我们需要遍历的具体位置。 3、当遍历完一圈的时候更新左上角元素和右下角元素。 细节: 当遍历最…...
每天几道Java面试题:集合(第四天)
目录 第四幕 、第一场)大厦楼下门口第二场)大门口 友情提醒 背面试题很枯燥,加入一些戏剧场景故事人物来加深记忆。PS:点击文章目录可直接跳转到文章指定位置。 第四幕 、 第一场)大厦楼下门口 【面试者老王,门卫甲…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
