【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(){ 阅读详情

相关推荐

stm32教程之三重ADC交错采样

ps:本文基于stm32F407ZGT6单片机 stm32F4单片机单通道采集的最大采样率为2.4M,所以有时会难以满足较高频率的采样,于是查阅芯片手册,发现stm32F4支持多重ADC采集,利用每个通道的转换时间,错位采样,从而提高采样率,最大把采样率开到2.4*3=7.2M. (去年初学ADC时研究的,基于cube和HAL库的三重ADC交错采样参考资料不多,我也是研究了一段时间,写下这篇博客希望可以帮助到更多人。) 示意图如下: 以下是官方例子的说明, In this ex...

weixin_52178036的博客 8877

详解ReentrantLock之Condition原理

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

Daniel的博客 1万+

NFS共享速度慢?麒麟系统性能调优5个关键参数实测对比

本文针对银河麒麟服务器系统上NFS共享速度慢的问题,通过实测对比分析了五个关键调优参数。重点探讨了rsize/wsize传输块大小、TCP/UDP协议选择、sync/async模式权衡等,并结合麒麟系统特性提供了具体的优化建议与配置示例,旨在帮助用户有效提升国产化环境下的文件共享性能。

weixin_29254029的博客 335

Java多线程中ReentrantLock与Condition详解

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

u013452337的博客 1917

从零开始学习信号完整性(SIPI)--2

上一节我们已经谈过,信号完整性研究的是如何使驱动器输出的信号传输到接收器件并被正确的接收。 信号完整性的三要素包含了:信号、驱动接收芯片、传输通道。 这其中信号是主体,我们要做的主要工作就是设计好信号的传输路径为信号的正确传输扫清障碍。要做信号完整性分析与设计首先要了解信号的特性,以及信号质量的判别标准。 对一个信号进行描述通常需要如下几个指标: 信号特性的描述 摆幅:信号从低电平到高电平之间的电压差,对于单端信号通常由信号的供电电压决......

qq_29476769的博客 2万+

第10篇:Agent + 爬虫 = 全自动数据采集专家

在企业级数据采集场景中,传统爬虫的痛点已经到了无法忽视的地步:而Agent + 爬虫的组合,就是这些痛点的终极解决方案。它的核心逻辑是:把爬虫从「人工写死的固定执行脚本」,升级为「能自主分析、自主决策、自主适配、自主修复的智能采集机器人」。我们在生产环境中做过对比测试:传统爬虫开发10个网站的采集脚本需要3人天,而Agent采集机器人只需要3分钟,页面改版后的修复成本从1人天降到了0,采集任务的成功率从62%提升到了95%以上。终端执行以下命令,安装基础依赖,与前9篇环境完全兼容: 二、核心能力拆解:Age

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1576

多线程篇 之 ReentrantLock 与 Condition

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

saiuna的博客 1314

大数据领域数据产品的交通运输行业应用

您是否经历过早高峰被堵在桥上,看着导航显示“前方5公里缓行”却无能为力?是否见过货车司机绕远路导致成本飙升?这些“交通痛点”的背后,是传统交通管理依赖经验决策的局限。本文将聚焦“大数据数据产品”这一核心工具,从技术原理到实际应用,全面解析它如何为交通运输行业“开天眼”,解决从城市拥堵到物流效率的一系列难题。本文将按照“问题引入→概念拆解→技术原理→实战案例→应用场景→未来趋势”的逻辑展开,用生活化比喻降低理解门槛,用代码和数学模型提升专业性,最终帮您建立“大数据+交通”的完整认知框架。交通数据。

操作系统内核探秘的博客 237

ReentrantLock中Condition的使用

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

sinat_38705282的博客 7110

手把手教程 | 使用 apktool 修改已发布 APK 的版本号与版本名称

摘要:本文介绍如何使用apktool工具直接修改APK版本信息,适用于版本回滚、多版本测试等场景。详细步骤包括反编译APK、修改版本号、重打包、对齐优化和重新签名,并分享了反编译相关实用知识。该方法无需源代码参与,但需注意修改后的APK必须重新签名才能安装。最后强调应在合法范围内使用反编译技术。

学无止境 827

3、流程引擎下载安装与部署

camunda有多种使用方式,此处先使用独立平台的方式部署引擎,这种用法适合分布式,微服务化,多语言异构系统的使用方式。

leyoliu的博客 5521

ReentrantLock 以及 Condition深度解析

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

zhujiangtaotaise的专栏 3094

XCP实战系列介绍01-测量与标定底层逻辑介绍

XCP-测量与标定底层代码实现介绍,通过对相关API调用关系介绍加深开发人员对其功能的了解。

initiallizer的博客 1万+

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

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

y245166349的专栏 1062

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

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

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

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

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

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

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

数字魔方操控师的博客 1149

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

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、付费专栏及课程。

余额充值