并发编程——CountDownLunch(闭锁)、CyclicBarrier(栅栏锁)、Semaphore(信号量)

本文主要是介绍并发编程——CountDownLunch(闭锁)、CyclicBarrier(栅栏锁)、Semaphore(信号量),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里写目录标题

  • CountDownLunch
  • CyclicBarrier
  • Semaphore

CountDownLunch

countDownLunch,又叫闭锁。它有三个关键的api:

  1. new CountDownLatch(count); 创建一个闭锁,并声明count的值
  2. countDownLatch.await(); 如果countDownLunch的count不是0,则阻塞当前线程直到count等0
  3. countDownLatch.countDown();将countDownLunch中的count减一

代码样例:

Logger logger = LoggerFactory.getLogger(this.getClass());
//创建一个count=1的闭锁
CountDownLatch countDownLatch = new CountDownLatch(1);
List<Thread> threads = new ArrayList<>();
//创建5个线程
for (int i = 0; i < 5; i++) {Thread thread = new Thread(() -> {logger.info("[{}]在等待发令枪", Thread.currentThread().getName());try {//等待闭锁的count=0countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}logger.info("枪响了,[{}]跑!", Thread.currentThread().getName());}, "t" + (i + 1));thread.start();threads.add(thread);try {//让出CPUTimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
}
logger.info("开枪,开跑!");
//将count--
countDownLatch.countDown();
try {//让出CPUTimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {e.printStackTrace();
}
//循环等待所有线程结束
for (Thread thread : threads) {try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}
}

运行结果:
countDownLunch测试结果
从结果中可以看出来,t1~t5是同时开跑的。需要注意的是,countDownLatch.await();会在count的值等于0时,唤醒被阻塞的线程,但是被唤醒的线程是否马上就可执行,这个要看CPU的调度,不一定被唤醒后,马上就可以执行。

上面是多等一的用法,下面来一个一等多的用法:

public static void main(String[] args) {int count = 5;CountDownLatch countDownLatch = new CountDownLatch(count);String[] list = new String[count];Random random = new Random();for (int i = 0; i < count; i++) {int finalI = i;Thread thread = new Thread(() -> {for (int j = 0; j <= 100; j++) {try {TimeUnit.MILLISECONDS.sleep(random.nextInt(200));} catch (InterruptedException e) {e.printStackTrace();}list[finalI]= Thread.currentThread().getName()+"("+j+"%)";System.out.print("\r"+ Arrays.toString(list));}countDownLatch.countDown();}, "t" + (i + 1));thread.start();}try {countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.print("\n结束了");
}

结果如下:
在这里插入图片描述

与join相比相同点:

  1. 都可以在某种程度上等待线程执行完毕

与join相比不同点:

  1. join是Thread的方法,需要持有Thread的引用,但是现在很多时候都是像线程池中提交任务的,很难拿到这个Thread的引用。但是CountDownLunch是可以作为全局变量的,这个引用比较好拿到。
  2. join是一定要等待线程结束的,但是CountDownLunch还是比较灵活的,可以在任意时刻countDown。

CyclicBarrier

CyclicBarrier,又叫栅栏锁

Logger logger = LoggerFactory.getLogger(this.getClass());
CyclicBarrier cyclicBarrier = new CyclicBarrier(2, ()->{logger.info("cyclicBarrier被置为0了,{}",Thread.currentThread().getName());
});
logger.info("cyclicBarrier初始化为2,{}",Thread.currentThread().getName());
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 4; i++) {Thread thread = new Thread(() -> {logger.info("cyclicBarrier -1,[{}]",Thread.currentThread().getName());try {cyclicBarrier.await();} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}logger.info("cyclicBarrier 0了,[{}]",Thread.currentThread().getName());}, "t" + (i + 1));thread.start();threads.add(thread);try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
}
//循环等待所有线程结束
for (Thread thread : threads) {try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}
}

执行结果:
cyclicBarrier
从执行结果可以看出来,cyclicBarrier是可以循环使用的,当cyclicBarrier的值=0时,会调用CyclicBarrier构造器中的runnable同时会将count重置为一开始设定的值。与countDownLunch相比:
相同点:

  1. 在count不等于0时,调用await的线程也是会阻塞的。

不同点:

  1. cyclicBarrier可以循环使用,countDownLunch是一次性的
  2. cyclicBarrier只要调用await就会使count-1,但是countDownLunch需要手动调用countDown方法

Semaphore

Semaphore,又叫信号量
信号量是用来限制一个时间点下,使用某资源的最大线程数。信号量限制的是线程数,而不是资源数

Semaphore semaphore = new Semaphore(3);
Logger logger = LoggerFactory.getLogger(this.getClass());
logger.info("初始化了一个大小为3的信号量。");
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 5; i++) {Thread thread = new Thread(() -> {logger.info("[{}]尝试申请一个资源",Thread.currentThread().getName());try {semaphore.acquire();logger.info("[{}]申请到了资源",Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}logger.info("[{}]释放了一个资源",Thread.currentThread().getName());semaphore.release();}, "t" + (i + 1));thread.start();threads.add(thread);try {//让出CPUTimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
}
//循环等待所有线程结束
for (Thread thread : threads) {try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}
}

执行结果:
Semaphore
在上面的代码中,首先创建了一个大小为3的信号量,然后创建了5个线程去依次申请资源。从日志中可以看出,线程123都顺利的拿到了资源,但是线程45在申请资源时发生了阻塞,当t1释放资源时,t4先获取到资源,t2释放资源时,t5获取到了资源。

这篇关于并发编程——CountDownLunch(闭锁)、CyclicBarrier(栅栏锁)、Semaphore(信号量)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/203631

相关文章

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Python 异步编程 asyncio简介及基本用法

《Python异步编程asyncio简介及基本用法》asyncio是Python的一个库,用于编写并发代码,使用协程、任务和Futures来处理I/O密集型和高延迟操作,本文给大家介绍Python... 目录1、asyncio是什么IO密集型任务特征2、怎么用1、基本用法2、关键字 async1、async

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.