【Java基础之线程同步(三)】使用ReentrantLock Condition实现线程同步

Java多线程5—ReentrantLock与Condition 文章目录1. ReentrantLock重入锁1.1 ReentrantLock源码解析1.1.1 lock操作1.1.2 release操作2. synchronized和Reetrantlock的区别3. Condition及其介绍3.1 Condition的介绍3.2 Condition在AQS中的使用3.3 Condition在阻塞队列中的实现4. [阻塞和唤醒线程——LockSupport功能简介及原理浅析](https://www.cnblogs.com/takumicx/p/9328459.h 阅读详情

java的java.util.concurrent.locks包内有Condition接口,该接口的官方定义如下:

Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.

Conditions (also known as condition queues or condition variables) provide a means for one thread to suspend execution (to "wait") until notified by another thread that some state condition may now be true. Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition. The key property that waiting for a condition provides is that it atomically releases the associated lock and suspends the current thread, just like Object.wait.

我们通过一个实际的例子来解释Condition的用法:

我们要打印1到9这9个数字,由A线程先打印1,2,3,然后由B线程打印4,5,6,然后再由A线程打印7,8,9. 这道题有很多种解法,现在我们使用Condition来做这道题(使用Object的wait,notify方法的解法在这里)。

package cn.outofmemory.locks;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class App {
	static class NumberWrapper {
		public int value = 1;
	}

	public static void main(String[] args) {
		//初始化可重入锁
		final Lock lock = new ReentrantLock();
		
		//第一个条件当屏幕上输出到3
		final Condition reachThreeCondition = lock.newCondition();
		//第二个条件当屏幕上输出到6
		final Condition reachSixCondition = lock.newCondition();
		
		//NumberWrapper只是为了封装一个数字,一边可以将数字对象共享,并可以设置为final
		//注意这里不要用Integer, Integer 是不可变对象
		final NumberWrapper num = new NumberWrapper();
		//初始化A线程
		Thread threadA = new Thread(new Runnable() {
			@Override
			public void run() {
				//需要先获得锁
				lock.lock();
				try {
					System.out.println("threadA start write");
					//A线程先输出前3个数
					while (num.value <= 3) {
						System.out.println(num.value);
						num.value++;
					}
					//输出到3时要signal,告诉B线程可以开始了
					reachThreeCondition.signal();
				} finally {
					lock.unlock();
				}
				lock.lock();
				try {
					//等待输出6的条件
					reachSixCondition.await();
					System.out.println("threadA start write");
					//输出剩余数字
					while (num.value <= 9) {
						System.out.println(num.value);
						num.value++;
					}

				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}

		});


		Thread threadB = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					lock.lock();
					
					while (num.value <= 3) {
						//等待3输出完毕的信号
						reachThreeCondition.await();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
				try {
					lock.lock();
					//已经收到信号,开始输出4,5,6
					System.out.println("threadB start write");
					while (num.value <= 6) {
						System.out.println(num.value);
						num.value++;
					}
					//4,5,6输出完毕,告诉A线程6输出完了
					reachSixCondition.signal();
				} finally {
					lock.unlock();
				}
			}

		});


		//启动两个线程
		threadB.start();
		threadA.start();
	}
}

 上述代码中有完整的注释,请参考注释,理解Condition的用法。

基本思路就是首先要A线程先写1,2,3,这时候B线程应该等待reachThredCondition信号,而当A线程写完3之后就通过signal告诉B线程“我写到3了,该你了”,这时候A线程要等嗲reachSixCondition信号,同时B线程得到通知,开始写4,5,6,写完4,5,6之后B线程通知A线程reachSixCondition条件成立了,这时候A线程就开始写剩下的7,8,9了。

为了更好的理解Condition的用法,我们再看下java官方提供的例子:

package locks;




import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;




public class AppOfficial {

	/**
	 * BoundedBuffer 是一个定长100的集合,当集合中没有元素时,take方法需要等待,直到有元素时才返回元素
	 * 当其中的元素数达到最大值时,要等待直到元素被take之后才执行put的操作
	 * @author yukaizhao
	 *
	 */
	static class BoundedBuffer {
		final Lock lock = new ReentrantLock();
		final Condition notFull = lock.newCondition();
		final Condition notEmpty = lock.newCondition();

		final Object[] items = new Object[100];
		int putptr, takeptr, count;

		public void put(Object x) throws InterruptedException {
			System .out.println("put wait lock");
			lock.lock();
			System.out.println("put get lock");
			try {
				while (count == items.length) {
					System.out.println("buffer full, please wait");
					notFull.await();
				}
					
				items[putptr] = x;
				if (++putptr == items.length)
					putptr = 0;
				++count;
				notEmpty.signal();
			} finally {
				lock.unlock();
			}
		}




		public Object take() throws InterruptedException {
			System.out.println("take wait lock");
			lock.lock();
			System.out.println("take get lock");
			try {
				while (count == 0) {
					System.out.println("no elements, please wait");
					notEmpty.await();
				}
				Object x = items[takeptr];
				if (++takeptr == items.length)
					takeptr = 0;
				--count;
				notFull.signal();
				return x;
			} finally {
				lock.unlock();
			}
		}
	}
	
	public static void main(String[] args) {
		final BoundedBuffer boundedBuffer = new BoundedBuffer();
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("t1 run");
				for (int i=0;i<1000;i++) {
					try {
						System.out.println("putting..");
						boundedBuffer.put(Integer.valueOf(i));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		}) ;
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i=0;i<1000;i++) {
					try {
						Object val = boundedBuffer.take();
						System.out.println(val);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		}) ;
		
		t1.start();
		t2.start();
	}
}

这个示例中BoundedBuffer是一个固定长度的集合,这个在其put操作时,如果发现长度已经达到最大长度,那么会等待notFull信号,如果得到notFull信号会像集合中添加元素,并发出notEmpty的信号,而在其take方法中如果发现集合长度为空,那么会等待notEmpty的信号,同时如果拿到一个元素,那么会发出notFull的信号。

Java进阶:ReentrantLock和Condition基本使用 1. 概述 Java除了使用synchronized锁之外,还可以使用ReentrantLock实现独占锁。ReentrantLock使用起来更加灵活,也提供了更丰富的功能。 2. 加锁解锁 验证加锁之前,先来看一段没加锁的代码 public class ReentrantLockApp { static class MyTest{ public volatile int num = 0; //自增 public void incr(){ 阅读详情

相关推荐

《AI应用架构师智能特征工程实践的前沿趋势解读》

面对传统方法的局限性,智能特征工程(Intelligent Feature Engineering)应运而生。智能特征工程是指利用人工智能、机器学习和自动化技术,实现特征提取、构造、选择和优化过程的自动化、智能化和可扩展化的方法和技术体系。效率提升:将数据科学家从繁琐的人工特征工程中解放出来,大幅缩短特征开发周期。质量保障:通过系统化方法发现人类难以察觉的特征模式,提高特征质量和模型性能。可扩展性:能够处理大规模、高维度和多类型的数据,适应不同领域和场景。降低门槛。

大数据洞察的博客 1181

详解ReentrantLock之Condition原理

Condition Jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock。虽然在性能上ReentrantLock和synchr...

Daniel的博客 1万+

论文阅读笔记---Deep HDR Video from Sequences with Alternating Exposures

Kalantari N K, Ramamoorthi R. Deep HDR Video from Sequences with Alternating Exposures[C]//Computer Graphics Forum. 2019, 38(2): 193-205. 摘要: 在本文中,提出了一种基于学习的方法来,我们使用两个顺序卷积神经网络(CNN)对整个HDR视频重建过程进...

qq_25283239的博客 1447

Java多线程中ReentrantLock与Condition详解

一、ReentrantLock类 1.1什么是reentrantlock java.util.concurrent.lock中的Lock框架是锁定的一个抽象,它允许把锁定的实现作为Java类,而不是作为语言的特性来实现。这就为Lock的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性...

u013452337的博客 1917

主升浪潜伏主图指标公式 提前潜伏,持仓待涨,通达信炒股指标公式

浙江世宝,第一次出现信号2022年6月1日,当日冲高回落,收涨3.48%,随后涨涨突破前高,回踩后出现第二次主升潜伏信号,时间2022年6月13日,当日收涨9.46%,后市连续涨停,走出12连板行情。九安医疗,第一次出现信号,黄色文字,当日2021年11月1日,涨幅0.19%,第二次出现信号一字涨停,没机会买进,第三次是T字,需要手快,后市连续上涨,接近20倍的大牛股。启明信息,突破区间后的回踩转涨位置出现信号,时间2021年11月29日,当日涨幅1.14%,次日爆发,波段涨幅152.65%。

weixin_69760830的博客 1880

虚拟零售智能客服架构设计:如何用大模型实现多轮对话与精准推荐?

想象一下,当你在一个电商平台购物时,遇到了一个能像你的专属导购一样,不仅能听懂你模糊的需求(“我想买一件适合夏天去海边玩,又能兼顾日常通勤的裙子”),还能记得你之前提到的尺码偏好和预算,甚至在你犹豫时,主动推荐几款符合你风格且正好有促销活动的商品——这不再是科幻电影中的场景,而是基于大语言模型(LLM)技术的新一代虚拟零售智能客服能够提供的体验。这一层是我们架构设计的重点,会在后续章节详细展开。如基于CRF、RNN的模型,或基于规则的状态更新,通常需要大量标注的对话状态数据,且对新领域、新槽位的适应性差。

Java大师兄的博客 1589

多线程篇 之 ReentrantLock 与 Condition

一、 ReentrantLock ReentrantLock是一个互斥锁,也是一个可重入的互斥锁。ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是相比功能更加丰富,添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。 先来看构造: //默认非公平锁 public ReentrantLock() { sync = new NonfairSync(); } // 可选是否公平锁 public ReentrantLock(boolean

saiuna的博客 1314

从零开始:TexLive(Latex)安装与配置全指南

本文提供了一份详尽的TexLive(Latex)安装与配置全指南,旨在帮助用户从零开始快速搭建LaTeX工作环境。内容涵盖从镜像下载、安装步骤详解、环境验证到高效编辑器(如VS Code)配置,并特别强调了中文排版支持与宏包管理,确保用户能顺利处理学术论文等专业文档的排版需求。

weixin_29284885的博客 903

ReentrantLock中Condition的使用

一、Condition的作用 ReentrantLock虽然实现了互斥,但是如何实现进程间的相互通信呢? 这就需要借助Condition来实现。 就像synchronized实现互斥,同时配合notify()和wait()方法来实现线程的通信一样。 Condition必须和Lock配合使用,其提供await()方法和signal()方法,作用类似wait()和notify(),用来实现线程间的通信。 二、具体实现 首先,我们创建一个ReentrantLock对象之后,调用该对象的newCondition

sinat_38705282的博客 7110

RuyiDify如何创建知识库API密钥:让程序安全访问知识库

知识库 API Key 是程序访问知识库的钥匙。创建它很简单,但真正重要的是知道它能做什么、应该放在哪里、不能暴露给谁。RuyiDify 讲这一步,不是为了让大家多记一个按钮,而是为了把知识库从“人工上传资料”推进到“程序化维护资料”。

未来已来,AI时代,学AI编程,做AI量化,就来大鹏AI教育。 136

uniapp - 实现手机端H5网页直播功能效果,拿到后端推流地址或播放资源后进行前端的流畅播放和画面展示功能,uniapp实时推流/拉流直播系统详细教程(提供完整示例代码,一键复制开箱即用!)

uniapp,h5网页,手机端H5网页,uniapp h5直播功能页面,uniapp直播实时推送显示,uniapp h5直播怎么做,怎么使用uniapp去实现移动端手机H5直播,h5 vue+uniapp怎么做直播,uniapp中使用videojs构建H5直播播放器,uniappH5端怎么实现直播推流,uniapp如何实现直播,直播聊天功能,h5平台端直播用什么插件,uniapp手机网页直播用什么组件插件播放器,uniapp手机H5直播播放器详细教程,直播项目,怎么使用vue+uniapp怎么做H5实时直播

✅ 精选推荐文章 8792

ReentrantLock 以及 Condition深度解析

前言 之前写过关于AQS的文章,也讲了关于 ReetrantLock 的源码分析。写ReentrantLock那么还是得提下 AQS 的。 一、关于AQS 中几个重要的属性 AQS 中维护了一个很重要的变量 state, 它是int型的,表示加锁的状态,初始状态值为0; 另外 AQS 还维护了一个很重要的变量exclusiveOwnerThread,它表示的是获得锁的线程,也叫独占线程,ReentrantLock中的可重入就是用到该属性,当 state != 0 但是 exclusiveOwnerThre

zhujiangtaotaise的专栏 3094

手把手教你学Simulink--双足机器人的反步控制方法仿真

本文介绍了在Simulink中基于反步控制方法进行双足机器人仿真研究的步骤。主要内容包括:1)准备工作,包括MATLAB/Simulink安装和相关工具箱配置;2)构建简化双足机器人模型;3)设计反步控制器,阐述其递归设计原理及Lyapunov函数构造方法;4)通过MATLAB Function块实现控制逻辑并连接模型;5)仿真参数配置和结果分析。文章强调反步控制适用于非线性系统,通过逐步构造虚拟控制律保证系统稳定性,并指出需要多次调试和查阅文献来优化控制效果。该教程为研究双足机器人运动控制提供了实用的仿真

MHD0815的博客 153

线程通信:wait/notify、Condition、CountDownLatch

在多线程并发编程中,线程并非孤立执行,常常需要协同工作完成复杂任务。例如生产者线程生产数据,消费者线程消费数据,二者需要通过通信协调生产和消费的节奏,避免数据积压或消费空数据。Java 提供了多种线程通信工具, 本文将从基础的 wait/notify 机制,到进阶的 Condition 接口,再到实用的并发工具类( CountDownLatch 、 CyclicBarrier 等),全面解析线程通信的实现原理与实战场景。

y245166349的专栏 1062

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Java技术——ReentrantLock的Condition的作用以及使用

0. 前言 之前知道ReentrantLock类有一个newCondition(),用于获取Lock上的一个条件,还可以多次newCondition()获得多个条件,Condition可用于线程间通信。是对比ReentrantLock和Synchronized关键字的区别时学习到的。但是有次面试被问到有没有用到过ReentrantLock的Condition,瞬间懵逼了。所以搜集了些资...

关于Android开发的一些技术点总结 ╮( ̄▽ ̄”)╭ 1万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Java 并发编程:使用 Lock 和 Condition 实现线程同步

Lock和Condition接口是 Java 并发编程中非常重要的工具,它们为开发者提供了比synchronized更灵活、更强大的同步机制。通过合理使用Lock和Condition,可以实现复杂的同步控制、高效的线程间通信,从而提升程序的性能和稳定性。在实际开发中,应根据具体的业务场景和需求,选择合适的同步方式。同时,在使用Lock和Condition时,要注意正确地获取和释放锁,避免出现死锁等问题。随着 Java 版本的不断更新,并发编程的工具和技术也在不断发展和完善。

数字魔方操控师的博客 1149

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

java多线程之Condition的使用

目录 一、Condition的概念 二、Condition的实现分析 (1)等待 (2)通知 三、Condition应用 (1)简单demo (2)可阻塞队列的应用案例 (3)多线程轮流执行 一、Condition的概念 回忆 synchronized 关键字,它配合 Object 的 wait()、notify() 系列方法可以实现等待/通知模式。对于 Lock,通过...

心猿意碼 1万+

ReentrantLock使用Condition实现线程的等待和唤醒

ReentrantLock ReentrantLock的出现是为了替代synchronized,因为使用lock锁之后代码会更加简洁,增加易读性,但是在jdk1.6之后,synchronized增加了一个锁升级的概念,所以从jdk1.6开始,都优先使用synchronized,这不代表着ReentrantLock就要废弃了,synchronized 是一个非公平锁,若要实现公平锁就得使用ReentrantLock;所以啊,没有万能的工具,但可以通过场景的不同而选择最适合的工具来使用; Condi...

叶新东老师的博客 2537

Java多线程 ReentrantLock与Condition

Java多线程 ReentrantLock与Condition 文章目录Java多线程 ReentrantLock与Condition

烟雨gps 1298

Java线程同步可重入锁ReentrantLock与Condition

Java面试核心知识点一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!Java面试核心知识点已经有读者朋友靠着这一份Java面试知识点指导拿到不错的offer了《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!外链图片转存中…(img-ZPzdQ2Cq-1712031385537)]Java面试核心知识点已经有读者朋友靠着这一份Java面试知识点指导拿到不错的offer了。

2401_84009626的博客 897

Java Condition接口:线程同步与通信机制

在当今的软件开发领域,高并发编程已成为一项至关重要的技能。特别是在处理大量用户请求或进行大数据处理时,如何有效地管理线程间的同步和通信,成为了提高系统性能和稳定性的关键。Java作为一门广泛应用于企业级应用开发的语言,提供了丰富的并发编程工具和API。其中,Condition接口是Java并发编程中的一个重要组成部分,它为线程间的通信提供了更为灵活和强大的机制。想象一下,在一个多线程环境中,线程A需要等待某个特定条件成立后才能继续执行,而线程B负责改变这个条件。

我是Java程序员廖志伟,感谢朋友们的支持! 966

ReentrantLock之Condition

1.介绍 等待/通知不仅可以使用0bject的wait()/notify()、notifyAll()方法。还可用通过RenntrantLock下面 的Condition来实现。 2.使用 /** * @Author AF * @Description * @Date 2019/12/28 18:19 */ public class ConditionMain { p...

dc630638147的博客 2439

Java多线程技术三:锁的使用——使用ReentrantLock类-1

在Java多线程中可以使用sunchronzied关键字来实现线程间同步,不过在JDK1.5中新增的ReentrantLock类也能达到同样的效果,并且在扩展功能上更加强大,比如具有嗅探锁定‘多路分支通知等功能。

geminigoth的博客 1178

ReentrantLock与Condition结合使用

ReentrantLock与Condition结合使用 线程之间协作:子线程循环2次,接着主线程循环4次, 接着又回到子线程循环2次,接着再回到主线程又循环4次,如此循环5次。

Stop Tears 4149
上一篇: 【Java基础之线程同步(二)】java线程同步:synchronized关键字,Lock接口以及可重入锁ReentrantLock
下一篇: 【数据库之事务(一)】事务是什么,以及事务四个特性,以及事务并发问题和隔离级别
cangchen
博客等级 码龄18年 108粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值