线程工具类-通过信号量、计时器等机制控制多线程之间的运行阻塞-笔记整理11

多线程使用信号量sem_init,sem_wait,sem_post 信号量的主要函数有:int sem_init(sem_t *sem,int pshared,unsigned int value); int sem_wait(sem_t *sem); int sem_post(sem_t *sem);sem_init用于对指定信号初始化,pshared为0,表示信号在当前进程的多个线程之间共享,value表示初始化信号的值。 sem_wait可以用来阻塞当前线程 阅读详情

线程工具类

1.Semaphore实现信号灯,可以控制访问线程的个数。信号量初始化10,最多只有10个线程并发访问

2.CyclicBarrier:提供一种阻塞机制,等待所有线程到达某一点集合之后,再继续向下运行

3.CountDownLatch:通过计数器技术,实现一同多,或多通知一

4.Exchanger:提供一种阻塞机制,实现俩个线程交换数据

 

 

1.Semaphore实现信号灯

一.概述:

Semaphore可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发问题。

  (1)Semaphore实现的功能就类似厕所有5个坑,假如有十个人要上厕所,那么同时能有多少个人上厕所呢?同时只能有5个人能够占用,当5个人中的任何一个人让开后,其中在等待的另外5个人中又有一个可以占用了。

  (2)另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项(构造函数参数配置)。

二.单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了”锁”,再由另一个线程释放锁,这可应用于死锁恢复的一些场合。

(解释:通过信号量来实现线程之间的互斥,其特点是可以由多个线程对信号量对象进行控制。锁的特点是当一个线程产生死锁,锁释放不了,别的线程肯定进不来。使用信号量,如果线程1死锁了,可以在另一个线程2中释放信号量,别的线程又可以进入)


代码示例:

public class SemaphoreTest {
	public static void main(String[] args) {
		ExecutorService execut=  Executors.newCachedThreadPool();
		
		final Semaphore semaphore = new Semaphore(3);
		
		for(int i=0;i<10;i++){
			 Runnable runnable = new Runnable(){
				  public void run() {
					    try {
					    	//获取信号量的许可
							semaphore.acquire();
						
					    } catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println("线程" + Thread.currentThread().getName() + "进入,当前已有" + (3-semaphore.availablePermits()) + "个并发");
						try {
							Thread.sleep((long)(4000));
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println("线程" + Thread.currentThread().getName() + "即将离开");			
						
						//释放信号量
						semaphore.release();
						
						System.out.println("线程" + Thread.currentThread().getName() + 
								"已离开,当前已有" + (3-semaphore.availablePermits()) + "个并发");
				  }
			 };
			 execut.execute(runnable);
		}
	}
}


2、CyclicBarrier:

在创建CyclicBarrier对象的时候,还可以传入一个Runnable当障碍点到齐后执行。

表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面,这就好比整个公司的人员利用周末时间集体郊游一样,先各自从家出发到公司集合后,再同时出发到公园游玩,在指定地点集合后再同时开始就餐。。。


代码示例:

public class CyclicBarrierTest {
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		
		final  CyclicBarrier cb = new CyclicBarrier(3,new Runnable() {
			           //当所有线程到达barrier时执行
			           @Override
			           public void run() {
			               System.out.println("Inside Barrier");
			               
			           }
			       });
		
		for(int i=0;i<4;i++){
			Runnable runnable = new Runnable(){
					public void run(){
					try {
						Thread.sleep((long)(Math.random()*10000));	
						System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));						
						cb.await();
						
						Thread.sleep((long)(Math.random()*10000));	
						System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
						cb.await();
						
						Thread.sleep((long)(Math.random()*10000));	
						System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));						
						cb.await();						
					} catch (Exception e) {
						e.printStackTrace();
					}				
				}
			};
			service.execute(runnable);
		}
		service.shutdown();
	}
}

 

3.CountDownLatch:

1.犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当计数到达0时。则所有等待者或单个等待者开始执行。这直接通过代码来说明CountDownLatch的作用,这样学员的理解效果更加直接。

2.可以实现一个人(也可以是多个人)等待其他所有人都来通知他,可以实现一个人通知多个人的效果,类似裁判一声口令,运动员同时开始奔跑,或者所有运动员都跑到终点后裁判才可以公布结果,用这个功能做百米赛跑的游戏程序不错哦

还可以实现一个计划需要多个领导都签字后才能继续向下实施的情况。


代码示例:

public class CountDownLatchTest {
	public static void main(String[] args) {
		ExecutorService service =	Executors.newCachedThreadPool();
		
		final CountDownLatch cdOrder = new CountDownLatch(1);
		final CountDownLatch cdAnswer = new CountDownLatch(3);
		
		for(int i=0;i<3;i++){
			 Runnable runnable = new Runnable(){
				 public void run() {
					    try {
					    	 System.out.println("线程"+Thread.currentThread().getName()+"正准备接收任务");
					    	 //cdOrder计数器不为0时,等待;当cdOrder计数器为0时,向下运行
					    	 cdOrder.await();
					    	
					    	 System.out.println("线程"+Thread.currentThread().getName()+"已接收任务");
					    	 
					    	 Thread.sleep((long)(Math.random()*10000));
					    	 
					    	 System.out.println("线程" + Thread.currentThread().getName() + "回应命令处理结果");	
					    	 
					    	//cdAnswer计数器减1,cdAnswer计数器为0,通知main线程运行	
					    	 cdAnswer.countDown();
					    } catch (InterruptedException e) {
							e.printStackTrace();
						}
				 }
			 };
			 service.execute(runnable);
		}
		try {
			Thread.sleep((long)(Math.random()*10000));
			System.out.println("线程"+Thread.currentThread().getName()+"即将发布任务");
            
			//cdOrder计数器减1,cdOrder计数器为0,通知其他线程运行	
			cdOrder.countDown();
			
			System.out.println("线程" + Thread.currentThread().getName() + "已发送命令,正在等待结果");	
			
			//等待cdAnswer计数器减为0
			cdAnswer.await();
			System.out.println("线程" + Thread.currentThread().getName() + "已收到所有响应结果");	
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		service.shutdown();
	}
}


4.Exchanger

用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据。

代码示例:

public class ExchangerTest {
	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		
		final Exchanger exchanger = new Exchanger();
		
		service.execute(new Runnable(){
			public void run() {
				try {				

					String data1 = "zxx";
					System.out.println("线程" + Thread.currentThread().getName() + "正在把数据" + data1 +"换出去");
					
					Thread.sleep((long)(Math.random()*10000));
					
					//通过Exchanger对象,等待换取俩线程间数据,等待另一个线程到来
					String data2 = (String)exchanger.exchange(data1);
					System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为" + data2);
				}catch(Exception e){
					
				}
			}	
		});
		
		service.execute(new Runnable(){
			public void run() {
				try {				
					String data1 = "lhm";
					System.out.println("线程" + Thread.currentThread().getName() + "正在把数据" + data1 +"换出去");
					
					Thread.sleep((long)(Math.random()*10000));		
					
					//通过Exchanger对象,等待换取俩线程间数据,等待另一个线程到来
					String data2 = (String)exchanger.exchange(data1);
					System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为" + data2);
				}catch(Exception e){
					
				}				
			}	
		});		
	}
}









数据库之Redis运维手册(私人整理) 1、redis配置文件 #cat 8000.conf daemonize no #[yes/no]默认值no,该参数用于定制redis服务是否以守护模式运行。 pidfile /var/run/redis.pid #默认值/var/run/redis.pid,指定redis服务的进程号文件路径,以守护模式运行时需要配置本参数; port 8000 #默认值6379,指定redis服务... 阅读详情

相关推荐

Linux 进程控制与进程互斥(附源代码)(附实验报告)

1、利用fork函数创建新进程,并根据fork函数的返回值,判断自己是处于父进程还是子进程中; 2、在新创建的子进程中,使用exec类的函数启动另一程序的执行;分析多进程时系统的运行状态和输出结果; 3、利用最常用的三个函数pthread_create,pthread_join和pthread_exit编写了一个最简单的多线程程序。理解多线程的运行和输出情况; 4、利用信号量机制控制多线程的运行顺序,并实现多线程中数据的共享; 5、分析Linux系统下多进程与多线程中的区别。

linux操作系统分析实验一

一、实验目的 1 理解Linux下进程的结构; 2 理解Linux下产生新进程的方法(系统调用—fork函数); 3 掌握如何启动另一程序的执行; 4 理解Linux下线程的结构; 5 理解Linux下产生新线程的方法; 6 理解Linux系统下多进程与多线程的区别 7 了解什么是管道 8 熟悉UNIX/LINUX支持的管道通信方式 9 理解内核模块的编写和装载方法 10 Gdb 调试工具的熟练使用 二 实验环境 Ubuntu linux 三 实验内容 1 利用fork函数创建新进程,并根据fork函

打工人的博客 3356

操作系统指导书

这是一份详细的指导书,里面利用信号量机制控制多线程的运行顺序,分析多线程中数据的共享情况; 5、分析Linux系统下多进程与多线程中的区别。

广州大学学生实验报告 ,实验一 进程控制与进程互斥

广州大学学生实验报告 ,实验一 进程控制与进程互斥,Linux操作系统分析

AABond的博客 2670

进程同步练习.

进程同步相关的习题 很具有代表性 希望各位能受益不少 主要是信号量机制 PV原语等知识

linux上实现多进程和多线程实现同步互斥(源代码)

在linux上分别用多进程和多线程实现的同步互斥操作(源代码)

《实战 Java 高并发程序设计》笔记——第3章 JDK 并发包(一)

文章目录3.1 多线程的团队协作:同步控制3.1.1 synchronized 的功能扩展:重入锁中断响应锁申请等待限时公平锁3.1.2 重入锁的好搭档:Condition 条件3.1.3 允许多个线程同时访问:信号量(Semaphore)3.1.4 ReadWriteLock 读写锁3.1.5 倒计时器:CountDownLatch3.1.6 循环栅栏:CyclicBarrier3.1.7 线程阻塞工具类:LockSupport 声明: 本博客是本人在学习《实战 Java 高并发程序设计》后整理的笔记,

bm1998 254

Linux进程创建与并发实验

熟悉linux环境的基本使用命令,熟悉使用vi、gdb、gcc等编程工具或软件 利用fork()函数创建子进程。

Python线程threading模块学习笔记

本文较为简略,仅作为整理笔记使用。 from threading import Event, Lock, RLock, Condition, Event(事件) 通过内部的标记True or False来实现线程间的通信。 构造:e = Event() 方法 说明 set() 将标记设置为True clear() 将标记设置为False is_set() 返回标记是否为...

Desperado的博客 319

Linux编程:普通文件和目录编程、进程实验、命名管道实验、信号实验、域名解析实验、网络服务器和客户机

Linux编程:普通文件和目录编程、进程实验、命名管道实验、信号实验、域名解析实验、网络服务器和客户机

mysql 计算不同胜率的活跃玩家的次日,3日,7日留存率

它根据每天的日期(logymd)和最高段位(max_rank)、胜率段落(win_rate_segment)进行分组,并计算总玩家人数(total_players)、第二天的留存人数(next_day_players)、第三天的留存人数(day3_players)和第七天的留存人数(day7_players)。注意:不是新手留存,是段位活跃玩家留存;最终的结果则是将留存数据进行展示,按照日期(date)、最高段位(rank_level)、胜率段落(win_rate_segment)进行排序。

weixin_42698221的博客 1836

进程与线程

Linux c处理并发通常会用到进程、线程、多路复用,这几个是最常用的也是最基础的,也准备需要找工作了,整理一下与这些相关的东西,发现光进程与线程就有很多内容,多路复用留到下篇写吧 一、进程 什么是一个进程?在操作系统原理使用这样的术语来描述的:正在运行的程序及其占用的资源(CPU、内存、系统资源等)叫做进程。 进程状态反映进程执行过程的变化。这些状态随着进程的执行和外界条件的变化而转换。在...

WuYujun's blog 429

【图像超分】论文复现:Pytorch实现SRCNN!保姆级复现教程!提供完整代码和最优权重模型(x2、x3、x4)!科研级论文曲线图!计算平均PSNR和SSIM!代码Windows和Linux都可用!

由于很多同学反应没用过jupyter notebook,更习惯用pycharm项目的形式跑代码。于是,本文将用pycharm项目的形式,重新复现SRCNN!【图像超分】论文复现:新手入门!Pytorch实现SRCNN,数据预处理、模型训练、测试、评估全流程详解,注释详细,简单修改就可以训练你自己的图像数据,有训练好的模型下载地址,随取随用。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 4702

高并发程序设计总结(一)JDK并发包

JDK并发包 文章目录JDK并发包同步控制工具synchronized 关键字Object.wait() 和 Object.notify() 方法ReentrantLock(可重入锁)Condition 条件变量 首先声明:这篇文档是对《Java高并发程序设计(第一版)》(高一鸣)这本书的总结,我摘取了一些关键的点,以介绍知识点、提问和回答的方式呈现。因此这篇总结并不适合没有任何多线程和高并发知识基础的人看,我第一次学多线程和并发的时候,完全云里雾里,一是由于之前操作系统这块我没学,二是因为Java 的并发

sty_dawang的博客 601

jira的详细使用教程

​jira的详细使用教程,1,Jira- 是一款缺陷管理软件工具,用其进行缺陷的管理和跟踪。(是B/S架构的软件) 2,主要涉及的角色: 3,具体工作流 添加工作流 1.点击项目设置

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 3295

Vulkan入门系列0- Vulkan与OpenGL的区别

虽然Vulkan和OpenGL都是对GPU的抽象,都能达到相同的功能,但它们的设计理念不同,可以说设计差异是非常之大,由于OpenGL从1992年到现在,已经有30多年的历史,GPU功能日新月异,与当年不可同日而语,在OpenGL保持向下兼容情况下,还要在OpenGL基础上设计一套编程接口显然是不可能的,所以推出了新编程规范Vulkan。另外在一些无窗口的应用中,Vulkan可以有选择的不创建帧缓冲区,比如在数学运算,物理模拟,处理视频流的应用中并不需要窗口,所以Vulkan支持更灵活的应用场景。

GPU全栈博主 4068

基于RT-Thread与STM32的RTC数字时钟:从硬件驱动到多线程应用实战

实时时钟(RTC)是嵌入式系统中实现精准时间基准的核心外设,它通过独立的电源域和BCD码计时机制,确保系统在掉电后仍能持续走时。其工作原理依赖于外部低速晶振(如32.768kHz LSE)提供时钟源,结合后备电池供电,为各类计时应用提供硬件保障。在技术价值上,RTC使得设备能够脱离网络独立运行,并支持定时唤醒、事件记录等关键功能。在应用场景中,它广泛用于智能家居、工业控制、穿戴设备等需要持续计时的领域。本文以STM32F407的RTC外设和1602 LCD模块为例,深入探讨了在RT-Thread实时操作系统

weixin_34072458的博客 363

嵌入式RTOS实战:uC/OS-III最新版移植指南(附项目源码)

本文提供uC/OS-III实时操作系统的完整移植指南,涵盖源码配置、工程搭建到任务调度的全流程。针对移植中的常见编译错误,给出关键修改方案(如中断重定义、配置使能等),附已验证的工程源码,通过LED任务实验验证稳定性,帮助开发者高效完成移植。适合嵌入式工程师及RTOS学习者参考。

Bit_Dong的博客 2472

Java多线程面试高频题全解析:从JMM原理到线程池实战排查

并发编程是Java后端开发的核心技能,多线程环境下如何保证数据一致性、原子性与可见性,是每一位开发者必须掌握的底层逻辑。Java内存模型(JMM)定义了主内存与工作内存的交互规则,而synchronized、volatile、CAS等机制则从不同层面解决了并发问题。理解这些原理,不仅有助于应对面试中的高频考点,更能指导工程实践。线程池作为资源管理的核心工具,其参数配置、任务执行流程和拒绝策略直接影响系统稳定性;ThreadLocal的合理使用与内存泄漏防范、死锁排查与jstack分析等实战技能,同样是衡量工

weixin_32612263的博客 349

YOLOv8独家原创改进:原创自研 | 自研独家创新DSAM注意力 ,基于BiLevelRoutingAttention注意力升级

提出新颖的注意力DSAM(Deformable Bi-level SpatialAttention Module),创新度极佳,适合科研创新,效果秒杀CBAM,Channel Attention+Spartial Attention升级为新颖的Deformable Bi-level Attention+Spartial Attention

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 1512

【32】C# WinForm入门到精通 ——打开文件OpenFileDialog 【属性、方法、事件、实例、源码】

本文介绍了WinForm开发中OpenFileDialog控件的关键属性及其应用。OpenFileDialog是.NET Framework提供的文件对话框控件,主要用于选择、打开文件操作。文章详细讲解了11个核心属性:AddExtension(自动补全扩展名)、AutoUpgradeEnabled(外观升级)、CheckFileExists/CheckPathExists(文件/路径存在验证)、DefaultExt(默认扩展名)、DereferenceLinks(解析快捷方式)、FileName/File

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 1534

《实战Java高并发程序设计》JDK并发包JUC--第三章

《实战Java高并发程序设计》JDK并发包/JUC–第三章 synchronized的扩展 重入锁:java.util.concurrent.locks.ReentrantLock public static ReentrantLock lock=new ReentrantLock(); @Overriede public void run(){ ​ lock.lock(); ​ try{ ​ .... ​ }finally{ ​ lock.unlock(); } } 由于这种锁一个

weixin_54241718的博客 231

工业相机通用SDK封装实战:C#硬件抽象层(HAL)实现多品牌无缝切换

本文介绍了一种解决工业相机SDK碎片化问题的通用解决方案。作者基于多年工业视觉项目经验,提出通过硬件抽象层(HAL)和适配器模式封装不同品牌相机的SDK差异,实现统一的相机操作接口。文章详细分析了传统直接对接SDK方式的四大痛点:接口碎片化、维护成本高、业务耦合度高和稳定性差,并给出了分层架构设计方案。该方案采用三层架构(业务层、抽象层、实现层),遵循最小接口原则和高内聚低耦合等设计理念,定义了包括触发模式、像素格式等通用枚举类型,以及图像数据结构等核心抽象。最终实现的HAL层能够支持多种品牌相机,显著降低

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 575

操作系统知识资料及对应简历书写分享

■ select bug(reactor的io多路检测模型不一定用的是epoll,还可能是select):当某个socket接收缓冲区有新数据字节到达,然后select报告这个socket描述符可读,但随后,协议栈检查到这个新字节检验和错误,然后丢弃这个字节,这时候调用read则无数据可读,如果socket没有被设置nonblocking,此read将阻塞当前线程。就是A线程在持有资源的同时想获取B线程的资源,B线程在持有资源的时候,想获取C线程的资源,C线程在持有资源的同时又想获取线程A的资源。

weixin_52259848的博客 840

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

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八股文学习记录

个人java学习

apple_74621612的博客 413

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: java5条件阻塞Condition的应用-多路等待通知Lock-Condition使用-笔记整理10
下一篇: 可阻塞的队列-笔记整理12
马克吐温
博客等级 码龄10年 11粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值