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

相关推荐

离心泵级间导叶的设计计算

离心泵级间导叶的设计计算高速离心泵级间流道的作用是将第一级复合叶轮流出的高速液流收集起来并送入第二级复合叶轮。级间流道的设计应考虑降低液体的流速,实现动能向压力能转化,减小液体的水力损失。级间流道主要有蜗壳形流道和导叶两种结构形...

cqzc55322的博客 2566

详解ReentrantLock之Condition原理

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

Daniel的博客 1万+

魔兽世界怀旧服宏命令全解析:从自动换装到智能判定,老玩家才知道的黑科技

本文全面解析魔兽世界怀旧服宏命令的高级应用,从自动换装到智能判定,揭秘老玩家专属的黑科技技巧。深入探讨怀旧服特有的宏命令机制,包括施法队列、装备切换系统和职业专属技巧,帮助玩家在经典旧世版本中提升战斗效率。

weixin_29230865的博客 731

Java多线程中ReentrantLock与Condition详解

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

u013452337的博客 1917

CCS20实战入门:第一个工程搭建示例

通过实际操作演示如何在ccs20中创建并配置首个开发项目,涵盖环境设置与基础调试步骤,帮助新手快速上手ccs20集成开发环境,提升嵌入式开发效率。

weixin_31185473的博客 885

Ubuntu20.04系统Cuckoo sandbox所需环境搭建及安装(超详细图文)

请勿叫我大神,我只是互联网的搬运工~ 前言 本教程以Ubuntu20桌面版作为示范,服务器版同样适用,但可能稍微麻烦一点,服务器版本的话安装Xmanage套装使用可能会相对轻松一些,由于后面会使用到vbox的使用,对vbox命令行操作不熟悉的小伙伴用xmanage可能会相对轻松一点。 提示:以下是本篇文章正文内容,下面案例可供参考 安装ubuntu20桌面版 步骤1:转到https://ubuntu.com/download/desktop下载下载.iso。 步骤2:使用您选择的虚拟机监控程序(VMWa

ElsonHY的博客 1万+

多线程篇 之 ReentrantLock 与 Condition

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

saiuna的博客 1314

Fortran基础编程(3)——格式化输出

本篇推文将进一步讲解Fortran基础语法中格式化输出与声明部分,让我们的代码更加美观起来吧~

qq_45715554的博客 3827

ReentrantLock中Condition的使用

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

sinat_38705282的博客 7110

RK3588S之CPU--benchmark(一)

本章会基于RK3588S来介绍有关CPU常用的benchmark工具及测试过程

文艺小少年的博客 1499

目标检测YOLO实战应用案例100讲-基于数据融合的SAR图像中海上目标检测与跟踪(中)

本文使用的数据集为欧空局(European Space Agency, ESA)提供的Sentinal-1 数据集,Sentinel-1是欧洲“哥白尼计划”的SAR卫星机群,主要是用于陆地和海 洋服务的极地轨道全天候昼夜雷达成像任务[ 34]。Sentinel-1A于2014年4月3日发 射升空,Sentinel-1B于2016年4月25日发射升空,每颗卫星都携带C波段SAR, 共同提供地球表面的全天候、昼夜图像。

qq_36130719的博客 356

ReentrantLock 以及 Condition深度解析

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

zhujiangtaotaise的专栏 3094

matlab 受约束的 Delaunay 三角剖分【2025最新版】

matlab内置调用函数实现受约束的 Delaunay 三角剖分并将结果保存为STL文件

点云侠的博客 1875

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

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

y245166349的专栏 1062

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

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

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

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

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

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

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

数字魔方操控师的博客 1149

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

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

余额充值