并发编程:线程同步基础:6 、在一个锁中使用2种条件

C#多线程与并发编程:从基础到高级的线程池与锁优化 C#中的线程池(ThreadPool)是一个管理一组线程的机制,它的目的是提高多线程操作的性能,避免频繁创建和销毁线程的开销。通过将线程复用,线程池显著减少了资源的消耗。线程池线程的创建和销毁由CLR自动管理,开发者不需要手动操作线程生命周期。线程池提供了一个线程管理机制,开发者可以将任务提交给线程池,线程池会在合适的时候从池中获取空闲线程来执行任务。 阅读详情

目录

1、实现内容

2、主程序

3、模拟文本文件

4、buffer中转(主要代码)

5、执行结果


1、实现内容

        创建1个生产者(写入程序)3个消费者(读取程序)和1个buff中转,以及1个模拟文本文件。

        生产者将文件内容读取后写入到buffer中转中(生产),消费者将buffer内容读取后打印(消费)。

        当buffer满时,生产者进入等待状态,当buffer为空时,消费者进入等待状态。

2、主程序

创建1个生产者和3个消费者。

package xyz.jangle.thread.test.n2_6.condition;

import java.util.concurrent.TimeUnit;

/**
 * 
 * 	2.6 在一个锁中使用2种条件
 *  生产者,即写入程序
 *  消费者,即读取程序
 *  缓冲,生产者和消费者的数据中转。
 * 
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年7月26日 上午7:39:31
 * 
 */
public class M {
	
	// 写进程的数量
	private static int wn = 1;
	// 读进程的数量
	private static int rn = 3;
	

	public static void main(String[] args) throws Exception {

		FileMock file = new FileMock(20, 5);
		Buffer buf = new Buffer(3);
		var sTime = System.currentTimeMillis();
		System.out.println(sTime);
		// 写入线程
		Thread[] wThreads = new Thread[wn];
		for (int i = 0; i < wn; i++) {
			Thread thread = new Thread(() -> {
				buf.setPendingLines(true);
				while (file.hasMoreLine()) {
					String line = file.getLine();
					if(line != null)	//如果写进程为2个,则需要加判断 2024年1月5日 09:16:30
					buf.insert(line);
				}
				buf.setPendingLines(false);
			});
			thread.start();
			wThreads[i] = thread;
		}
		Thread[] rThreads = new Thread[rn];
		for (int i = 0; i < rn; i++) {
			Thread thread = new Thread(() -> {
				while (buf.hasPendingLines()) {
					buf.get();
					try {
						TimeUnit.SECONDS.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
			thread.start();
			rThreads[i] = thread;
		}
		for(Thread w:wThreads) {
			w.join();
		}
		for(Thread r:rThreads) {
			r.join();
		}
		System.out.println(System.currentTimeMillis() - sTime);

	}

}

3、模拟文本文件

package xyz.jangle.thread.test.n2_6.condition;

/**
 * 
 * 模拟文本文件
 * 
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年7月25日 下午10:04:30
 * 
 */
public class FileMock {

	// 正文((行)
	private String[] content;
	// 行
	private int index;

	public FileMock(int size, int length) {
		content = new String[size];
		for (int i = 0; i < size; i++) {
			StringBuilder row = new StringBuilder(length);
			for (int j = 0; j < length; j++) {
				int rChar = (int) (Math.random() * 255);
				row.append(rChar);
			}
			content[i] = row.toString();
		}
		index = 0;
	}

	/**
	 * 是否还有行(即末尾了没)
	 * 
	 * @author jangle
	 * @time 2020年7月25日 下午10:09:52
	 * @return
	 */
	public boolean hasMoreLine() {
		return index < content.length;
	}

	/**
	 * 获取行
	 * 
	 * @author jangle
	 * @time 2020年7月25日 下午10:12:02
	 * @return
	 */
	public synchronized String getLine() {//如果写进程为2个,则需要加上同步。2024年1月5日 09:16:07
		if (this.hasMoreLine()) {
			System.out.println("Mock:" + (content.length - index));
			return content[index++];
		}
		return null;
	}

}

4、buffer中转(主要代码)

package xyz.jangle.thread.test.n2_6.condition;

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

/**
 * 数据缓冲区,建立在生产者和消费者之间。
 * 
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年7月25日 下午10:12:59
 * 
 */
public class Buffer {

	// 存放共享数据
	private final LinkedList<String> buffer;
	// 缓冲区长度
	private final int maxSize;

	private final ReentrantLock lock;

	private final Condition insertCondition;

	private final Condition getCondition;

	private boolean pendingLines;

	public Buffer(int maxSize) {
		super();
		this.maxSize = maxSize;
		this.lock = new ReentrantLock();
		insertCondition = lock.newCondition();
		getCondition = lock.newCondition();
		pendingLines = true;
		buffer = new LinkedList<String>();
	}

	// 插入缓冲数据
	public void insert(String line) {
		lock.lock();
		try {
			while (buffer.size() == maxSize) {
				System.out.println(Thread.currentThread().getName()+"缓冲区已满,进入等待");
				insertCondition.await();
			}
			buffer.offer(line);
			System.out.println(Thread.currentThread().getName()+"插入了一行记录"+line);
			getCondition.signalAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}

	// 获取缓冲数据
	public String get() {
		String line = null;
		lock.lock();
		try {
			// 当缓冲区没有内容,但文本文件中还有未写入的内容时,进行等待。
			while((buffer.size() == 0) && (hasPendingLines())) {
				System.out.println(Thread.currentThread().getName()+"缓冲区已空,进入等待");
				getCondition.await();
			}
			if(hasPendingLines()) {
				line = buffer.poll();
				System.out.println(Thread.currentThread().getName()+"读取了一行数据"+line+"缓冲区还剩:"+buffer.size());
				insertCondition.signalAll();
			}
		} catch (Exception e) {
		}finally {
			lock.unlock();
		}
		return line;
	}
	
	/**
	 * 	用于设置是否还有文本内容(在文本文件内容全部写入缓冲后设置为false)
	 * 
	 * @author jangle
	 * @time 2020年7月26日 上午7:59:13
	 * @param pendingLines
	 */
	public synchronized void setPendingLines(boolean pendingLines) {
		this.pendingLines = pendingLines;
	}
	
	/**
	 *  是否还有未处理的文本内容(文本文件内容 || 缓冲文件内容)
	 * 
	 * @author jangle
	 * @time 2020年7月26日 上午7:58:32
	 * @return
	 */
	public synchronized boolean hasPendingLines() {
		return pendingLines || buffer.size() > 0;
	}
	

}

5、执行结果

1704423262311
Mock:20
Thread-0插入了一行记录201246130116
Mock:19
Thread-0插入了一行记录131291943819
Mock:18
Thread-3读取了一行数据201246130116缓冲区还剩:1
Thread-0插入了一行记录21723025351228
Mock:17
Thread-1读取了一行数据131291943819缓冲区还剩:1
Thread-2读取了一行数据21723025351228缓冲区还剩:0
Thread-0插入了一行记录16195135235153
Mock:16
Thread-0插入了一行记录214134140210184
Mock:15
Thread-0插入了一行记录1931514111087
Mock:14
Thread-0缓冲区已满,进入等待
Thread-1读取了一行数据16195135235153缓冲区还剩:2
Thread-2读取了一行数据214134140210184缓冲区还剩:1
Thread-3读取了一行数据1931514111087缓冲区还剩:0
Thread-0插入了一行记录861591085822
Mock:13
Thread-0插入了一行记录1487796124227
Mock:12
Thread-0插入了一行记录21624569179235
Mock:11
Thread-0缓冲区已满,进入等待
Thread-1读取了一行数据861591085822缓冲区还剩:2
Thread-2读取了一行数据1487796124227缓冲区还剩:1
Thread-3读取了一行数据21624569179235缓冲区还剩:0
Thread-0插入了一行记录6219799204240
Mock:10
Thread-0插入了一行记录936822910658
Mock:9
Thread-0插入了一行记录201565732128
Mock:8
Thread-0缓冲区已满,进入等待
Thread-2读取了一行数据6219799204240缓冲区还剩:2
Thread-3读取了一行数据936822910658缓冲区还剩:1
Thread-1读取了一行数据201565732128缓冲区还剩:0
Thread-0插入了一行记录1996321252179
Mock:7
Thread-0插入了一行记录21313993322
Mock:6
Thread-0插入了一行记录66215619465
Mock:5
Thread-0缓冲区已满,进入等待
Thread-3读取了一行数据1996321252179缓冲区还剩:2
Thread-1读取了一行数据21313993322缓冲区还剩:1
Thread-2读取了一行数据66215619465缓冲区还剩:0
Thread-0插入了一行记录201215617117
Mock:4
Thread-0插入了一行记录1361563315546
Mock:3
Thread-0插入了一行记录23422921188193
Mock:2
Thread-0缓冲区已满,进入等待
Thread-1读取了一行数据201215617117缓冲区还剩:2
Thread-2读取了一行数据1361563315546缓冲区还剩:1
Thread-3读取了一行数据23422921188193缓冲区还剩:0
Thread-0插入了一行记录2063187172139
Mock:1
Thread-0插入了一行记录11180225171
Thread-3读取了一行数据2063187172139缓冲区还剩:1
Thread-1读取了一行数据11180225171缓冲区还剩:0
7053

python并发编程之线程同步 在并发编程中,线程同步是一种重要的机制,用于确保多个线程之间的正确性和一致性。Python提供了几种线程同步的机制,包括锁、条件变量和信号量。下面我们将介绍这些机制,并列举10个实用的场景代码。 阅读详情

相关推荐

并发编程——线程——锁

并发编程中避免不了在同一时间对同一数据的更改,因此,对锁的使用变得尤为重要,什么时间、什么场景该用什么类型的锁都是有讲究的,接下来介绍几种常见的锁。 死锁现象 问题产生需求,在学新的锁之前先来看看我们学的互斥锁有什么缺点。 所谓死锁,就是指两个或两个以上的进程或线程在执行过程中因争夺资源而造成的一种互相等待的现象,若无外力的作用,它们都将无法推进下去。 此时称系统处于死锁状态或系统产生了死锁,这些...

Alex 626

Java并发编程:理解线程、同步和锁

Java提供了一套完备的并发编程工具,从基本的线程控制到复杂的锁机制和并发集合,这些工具帮助开发者构建稳健的多线程应用程序。原子类提供的主要优势是无锁的线程安全性,这通常比使用锁或其他同步机制具有更高的性能,特别是在高竞争的环境中。在Java并发编程中,除了锁和同步方法,条件变量和阻塞队列也是重要的工具,用于在多线程环境中协调线程之间的操作。阻塞队列是支持两个附加操作的队列,这些操作包括在队列为空时队列的获取操作将阻塞,等待队列变为非空,当队列满时插入操作将阻塞,等待队列可用。

宋小黑的博客 1566

Java并发编程:使用锁和条件接口同步访问共享资源

本章介绍了在Java中如何通过Lock和Condition接口实现线程之间的同步,以安全地访问共享资源。通过使用SynchronizedBuffer类的实例来展示生产者和消费者线程如何合作,确保数据的一致性和完整性。此外,还讨论了多线程编程中GUI应用的特殊挑战以及如何利用SwingWorker类在后台线程中进行长时间计算,并在事件分发线程中更新GUI。

weixin_35391606的博客 277

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

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

数字魔方操控师的博客 1149

第17篇:深入解析OpenEuler 24.03系统中的逻辑卷管理(LVM)

OpenEuler 24.03系统中的逻辑卷管理(LVM)提供了灵活的存储管理方案,通过在物理存储与文件系统间构建抽象层实现动态资源分配。

专注于系统运维、数据库、DevOps、虚拟化技术、docker、kubernetes、等云原生技术。 1689

基于PSO-BP神经网络的风电功率预测研究论文复现

风电功率预测。基于PSO-BP神经网络的风电功率预测论文复现。matlab程序,注释清晰。

weixin_825487230的博客 2294

Python并发编程 05 锁、同步条件、信号量、线程队列、生产者消费者模型

Python并发编程 05 锁、同步条件、信号量、线程队列、生产者消费者模型

weixin_42830015的博客 1267

CIC-IDS2017数据集训练和测试

1、数据集预处理 1.1整合数据并剔除脏数据 如上图所示,整个数据集是分开的,想要训练,必须要整合在一起,同时在数据集中存在Nan和Infiniti脏数据(只有第15列和第16列存在)需要剔除: 具体代码如下: ```python importpandasaspd #按行合并多个Dataframe数据 defmergeData(): monday=writeData("data\MachineLearningCVE\Monday-W...

蓝亚之舟的博客 2万+

Java中的并发编程:理解和应用线程、同步与锁

随着对这些基本概念的掌握,开发者可以进一步探索更高级的并发编程技术,如`Executor`框架、并发集合和原子变量等,以解决更复杂的并发问题。- **实现`Runnable`接口**:创建一个新的类实现`Runnable`接口,并实现`run`方法。- **同步块**:通过`synchronized`关键字锁定一个特定的对象,只有获得该对象锁的线程才能执行同步块中的代码。- **继承`Thread`类**:创建一个新的类继承自`Thread`类,并重写`run`方法。#### 3. 锁的应用。

youmashengyue的博客 1098

Vivado实战:AXI转PCIe IP核配置全流程(含性能优化技巧)

本文详细介绍了在Vivado环境中配置AXI转PCIe IP核的全流程,包括工程准备、IP核参数设置、BAR空间配置、中断系统优化以及TLP传输效率提升等关键步骤。特别分享了经过验证的性能优化技巧,帮助开发者显著提升PCIe链路的吞吐量和稳定性,适用于视频采集、高速数据记录等应用场景。

weixin_30892037的博客 551

STM32输入捕获功能,同时捕获8路波形。

STM32输入捕获功能,使用TIM2和TIM3同时捕获8路波形。 工作上的一个需求,要采集两组控制步进电机的信号。就是采集8个通道的方波,测量频率和计脉冲个数。看起来简简单单的东西,磕磕碰碰搞了两天,走了一些弯路,这里写出来记录一下。顺便理解一下输入捕获个多种用法。 1. 硬件设计 首先看一下用到那些IO口。在STM32手册里找这样TIMx_CHx的就是输入捕获的口了。 这里用了TIM2的4个口和TIM3的4个口。 定义 端口 TIM2_CH1 PA0 TIM2_CH2 PA1 TI

qq_36353009的博客 5122

【Java 并发编程】理解同步锁、可重入锁与死锁问题

根据程序的多次运行,发现结果总是随机且小于 100000 的数,原因是只要有锁就已经满足了进入同步方法或者同步代码块的资格,而不同的对象产生的锁也是不同的,以上 t1 线程拿到了 o1 对象的锁,t2 线程拿到了 o2 对象的锁,两个线程都可以自由的访问 run ,程序就又并发执行了。关于代码块的锁对象,其实只要是一个对象就行,可以是当前对象的 this,也可以是当前类的class, 也可以用 Object 或者 Object 的子类创建的对象都可以。,也就是说 t1 线程还是可以拿到锁的。

2301_79201049的博客 1605

使用Intel编译器编译OpenFOAM

本文总结了使用INTEL编译器编译OpenFOAM的过程

姜蜉蝣的博客 1546

多线程(二) 同步 锁对象和条件对象

什么是线程同步? 当使用多个线程来访问同一个数据时,非常容易出现线程安全问题(比如多个线程都在操作同一数据导致数据不一致),所以我们用同步机制来解决这些问题。 锁对象  在Java SE5.0引入ReentrantLock类。Lock是Java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定

ying847782627的博客 3007

从零开始学 AUTOSAR:深入浅出 SAE J1939 诊断通信管理器(J1939Dcm)深度完整版

SAE J1939 是美国汽车工程师学会制定的重型车辆 CAN 总线通信标准,覆盖卡车、客车、工程机械、农机、船舶等,是商用车领域的 “通用语言”。基于CAN 2.0B 扩展帧(29 位 ID)(车规主流)PGN(参数组号)+ SPN(可疑参数号)核心标准:J1939-21:数据链路层(CAN 帧格式、地址声明)J1939-71:应用层(普通信号、报文)诊断层(核心!J1939Dcm 依据)J1939-81:网络管理(地址管理、节点检测)

getusushu的博客 110

SAP公司间STO业务解析(包含主数据解析、后台配置解析、前台业务演示)

SAP公司间STO业务解析

ww114784的博客 1016

Python 并发编程中的锁(Lock)、可重入锁(RLock)、条件变量(Condition)

锁(Lock)、可重入锁(RLock)和条件变量(Condition)是 Python 并发编程中不可或缺的工具。它们分别解决了不同的同步问题,帮助开发者构建高效且安全的多线程程序。在实际开发中,应根据具体需求选择合适的同步机制,以确保程序的正确性和性能。```

2501_91113634的博客 1425

NTscan扫描工具

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

并发编程 - 线程同步(六)之锁lock

其工作原理也很简单,就是通过lock创建一个互斥锁,当一个线程获取到此互斥锁则此线程可以进入被lock保护的代码块,同时其他线程将被阻塞无法进入此代码块,直至第一个线程释放此互斥锁,其他线程才可以获取此互斥锁并进入代码块。2.外部可见性:this表示当前实例的引用,它是公共的,因此外部代码也可以访问,这也就意味着外部代码可以通过lock(实例)访问lock(this)锁,从而使同步机制失去控制。Console.WriteLine($"进入时间 {DateTime.Now:HH:mm:ss}");

weixin_55010563的博客 1115

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

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...

Java的多线程之同步篇一:锁对象、条件对象

一、多线程的同步 根据各线程访问数据的次序,可能会产生讹误的对象。这样一种情况通常称为竞争条件。 1>同步存取(以银行转账为例:) 模拟一个有若干个账户的银行,随机地生成在这些账户之间转换钱款的交易。每个账户有一个线程。每笔交易中,会从线程所服务的账户中随机转移一定数目的钱款到另一个随机账户。 提示:银行内部的转账交易,银行的总金额应保持不变。 代码如下: package com.

◇″淡定。 2527

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

基于Java的锁、多线程、线程池并发编程

背景 操作系统 所有计算机资源是被一个程序独占的,称为裸机 能够协调程序排队的简单批处理系统 当程序遇到IO之类的阻塞时,处理器转而处理其他程序,称作多道批处理系统 给每个程序都分配一点处理器时间去轮流执行,每个程序分配到的执行时间就叫做时间片,这个过程也叫做分时处理。操作系统负责管理时间片具体设置为多大,处理器怎么切换各个程序的执行 4核、8核即多个处理器 进程 进程的两个特点:资源所有权...

byr_wy的博客 1800

使用条件变量时为啥一定要指定一个锁?

今天看代码的时候突然发现了这个问题。 条件变量wait的时候必须指定一个已经get到了的锁。 去网上搜了一下发现至少是中文范围内,全网都不知道为什么。后来我想了一下,应该是这样的。先看使用情景。 以盖小区为例。 a负责盖房子,x负责装窗子,y负责粉刷,z负责安装电路。 所以4个人做事时,房子所在的土地就是被竞争的资源。我们来看看小区怎么个盖法。 肯定要a先工作,xyz等待a完工才能一个一

madbunny的专栏 5543

同步方法中的锁对象_java多线程并发编程(二) 线程同步

一、为何会线程不安全 1、方法内的变量为线程安全“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得结果也就是“线程安全”的了。方法中的变量不存在非线程安全问题,永远都是线程安全的。这是方法内部的变量是私有的特性造成的。 2、实例变量非线程安全如果多个线程共同访问1个对象中的实例变量,则有可能出现“非线程安全”问题。两个线程同时访问一个没有同步的方法...

weixin_35023786的博客 1459

C++并发编程:线程与锁的应用

C++并发编程中线程与锁的应用是提高程序性能和响应速度的关键技术。本文详细阐述了线程与锁的基本概念、用法以及同步策略,并通过示例代码展示了如何在实际编程中使用这些技术。通过掌握线程与锁的应用,开发者可以有效地提高程序在多核处理器上的执行效率。在未来,随着计算机硬件的发展,并发编程的重要性将越来越突出。因此,深入研究并发编程技术,探索更高效的线程与锁的同步策略,将是软件开发领域的重要研究方向。同时,开发者也需要不断学习和实践,以提高自己在并发编程方面的技能和经验。

2501_92487565的博客 342

Java - 并发编程:同步方法的锁对象与锁竞争

并发编程:同步方法的锁对象与锁竞争1 示例描述2 同步方法的锁对象3 静态同步方法的锁对象 1 示例描述 示例:定义线程任务类如下所示: public class SynObj { public synchronized void showA(){ System.out.println("showA.."); try { Thread.sleep(3000); } catch (Interr

xing123456jl的博客 301
上一篇: 并发编程:线程同步基础:5、读写锁。ReentrantReadWriteLock
下一篇: 并发编程:线程同步基础:7、StampedLock DEMO
博风
博客等级 码龄16年 442粉丝 357原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值