网站前台开发由什么做的/百度一下网页版搜索引擎
一、什么是CountDownLatch
CountDownLatch中count down是倒数的意思,latch则是门闩的含义。整体含义可以理解为倒数的门栓。
CountDownLatch的作用也是如此,在构造CountDownLatch(int count):的时候需要传入一个整数count,在这个整数“倒数”到0之前,主线程需要等待在门口,而这个“倒数”过程则是由各个执行线程驱动的,每个线程执行完一个任务“倒数”一次。
总结来说,CountDownLatch是Java中一个多线程工具类,用于控制线程的顺序,可以让主线程等待其他线程完成任务之后再继续执行,或者让多个线程之间相互等待。
二、主要方法
- CountDownLatch(int count):构造方法,创建一个新的 CountDownLatch 实例,用给定的计数初始化。参数 count 表示线程需要等待的任务数量。
int numberOfTasks = 5;
CountDownLatch latch = new CountDownLatch(numberOfTasks);
- void await():使当前线程等待,直到计数器值变为0,除非线程被 interrupted。如果计数器的值已经为0,则此方法立即返回。在实际应用中,通常在主线程中调用此方法,等待其他子线程完成任务。(会使线程休眠,直到countDownLatch的值递减到0,才会重新就绪)
latch.await();
- boolean await(long timeout, TimeUnit unit):使当前线程等待,直到计数器值变为0,或者指定的等待时间已到,或者线程被 interrupted。如果计数器的值已经为0,则此方法立即返回。
- 参数 timeout 是指定的等待时间,
- 参数 unit 是 timeout 的单位(如秒、毫秒等)。
此方法返回一个布尔值,表示在等待时间内计数器是否变为0。
latch.await(5, TimeUnit.SECONDS);
这里需要注意的是,await()方法并没有规定只能有一个线程执行该方法,如果多个线程同时执行await()方法,那么这几个线程都将处于等待状态,并且以共享模式享有同一个锁。
- void countDown():递减计数器的值。如果计数器的结果为0, 则释放所有等待的线程。在实际应用中,通常在线程完成任务后调用此方法。
latch.countDown();
这里需要注意的是,countDown()方法并没有规定一个线程只能调用一次,当同一个线程调用多次countDown()方法时,每次都会使计数器减一;
- long getCount():获取当前计数的值。返回当前 CountDownLatch 实例内部的计数值。
long remainingCount = latch.getCount();
三、优缺点
- 优点
- 简化了线程间的通信和同步。在某些并发场景中,需要等待其他线程完成任务后才能继续执行,使用 CountDownLatch 可以简化这种操作,而不需要复杂的锁和等待/通知机制。
- 提高性能。由于 CountDownLatch 可以让线程在完成任务后立即递减计数值,而不需要等待其他线程完成任务,因此可以减少阻塞,提高程序运行性能。
- 支持灵活的计数。可以通过创建不同的 CountDownLatch 实例,实现对多个线程任务计数。
- 缺点:
- 单次使用。CountDownLatch 的计数值无法重置。一旦计数值到达零,它就不能再被使用了。在需要重复使用的场景中,可以选用 CyclicBarrier 或 Semaphore。
- 没有返回值。CountDownLatch 无法获得执行任务的线程所返回的结果。如果需要收集线程执行结果,可以考虑使用 java.util.concurrent.Future 和 java.util.concurrent.ExecutorService。
四、使用场景
- 启动多个线程执行并行任务,主线程等待所有并行任务完成后继续执行。
例如:在测试中,准备数据阶段,需要同时查询多个子系统的数据和处理,等待处理结束后再进行下一步操作。 - 控制线程的执行顺序。一个线程需要等待其他线程的结果或者完成任务后才能继续执行。
例如:一个文件解压缩程序,首先需要下载文件,下载完成后解压文件。 - 实现一个计数器,允许一个或多个线程等待直到计数器为0。这对于在系统初始化时,需要等待资源加载或者初始化的场景十分有用。
例如:等待加载配置文件、启动连接池等操作完成后才开始处理其他任务。
五、示例代码
1、一个简单示例代码
在这个例子中,创建了5个线程,并让每个线程睡眠1秒钟,表示完成一个任务。在每个线程完成任务后,调用了countDown()方法,计数器减1。
在主线程中,调用了await()方法,等待所有线程完成任务。当所有线程的计数器都减为0时,主线程才会继续执行,输出"All tasks done"。
import java.util.concurrent.CountDownLatch;public class CountDownLatchExample {public static void main(String[] args) throws InterruptedException {int n = 5; // 等待5个线程完成任务CountDownLatch countDownLatch = new CountDownLatch(n);for (int i = 0; i < n; i++) {Thread t = new Thread(() -> {try {System.out.println(Thread.currentThread().getName() + " is working");Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " done");countDownLatch.countDown(); // 计数器减1} catch (InterruptedException e) {e.printStackTrace();}});t.start();}countDownLatch.await(); // 等待其他线程完成任务System.out.println("All tasks done");}
}
输出结果:
Thread-0 is working
Thread-1 is working
Thread-2 is working
Thread-3 is working
Thread-4 is working
Thread-2 done
Thread-1 done
Thread-0 done
Thread-4 done
Thread-3 done
All tasks done
2、启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行
package base.threadabout.multhread.countdownlatch;import java.util.concurrent.*;/*** CountDownLatch常用方法:await(),await(long,TimeUnit),countDown()* await()会使线程休眠,直到countDownLatch的值递减到0,才会重新就绪* await(long, TimeUnit) 休眠,直到countDownLatch的值递减到0或休眠时间结束* 大概作用:等所有线程&某些线程都执行完了,再统一执行某个具体功能*/
public class MainLoadingService {public static void main(String[] args) throws InterruptedException {CountDownLatch cdl = new CountDownLatch(5);ExecutorService pool = Executors.newFixedThreadPool(5);for (int i = 0; i < 5; i++) {Loading runnable = new Loading(cdl);pool.execute(runnable);}// 线程全部跑完的标志System.out.println("等待子线程加载组件...");cdl.await();System.out.println("所有组件加载完毕,继续执行...");pool.shutdown();}
}class Loading implements Runnable {private CountDownLatch countDownLatch;public Loading(CountDownLatch countDownLatch) {this.countDownLatch = countDownLatch;}@Overridepublic void run() {// 处理业务String name = Thread.currentThread().getName();System.out.println("子线程:" + name + "正在加载组件...");// 业务处理完毕,countDownLatch-1countDownLatch.countDown();}
}
结果:
等待子线程加载组件...
子线程:pool-1-thread-1正在加载组件...
子线程:pool-1-thread-2正在加载组件...
子线程:pool-1-thread-3正在加载组件...
子线程:pool-1-thread-4正在加载组件...
子线程:pool-1-thread-5正在加载组件...
所有组件加载完毕,关闭线程池pool...
3、示例
主线程定义new CountDownLatch(1)。每个子线程先执行await(),进入等待。等待所有子线程都开启,主线程执行countDown(),能确保所有子线程同时开始处理任务。
类似于赛跑,子线程是运动员,await是运动员的预备阶段,主线程是裁判,countDown是裁判的发令枪。枪响运动员才能跑。
package base.threadabout.multhread.countdownlatch;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class RaceGame {public static void main(String[] args) throws InterruptedException {ExecutorService pool = Executors.newFixedThreadPool(5);CountDownLatch countDownLatch = new CountDownLatch(1);for (int i = 0; i < 5; i++) {Player player = new Player(i, countDownLatch);pool.execute(player);}Thread.sleep(1000);System.out.println("所有选手各就位.....GO!");countDownLatch.countDown();pool.shutdown();}static class Player implements Runnable{private int id;private CountDownLatch countDownLatch;public Player(int id, CountDownLatch countDownLatch) {this.id = id;this.countDownLatch = countDownLatch;}@Overridepublic void run() {System.out.println("参赛选手[" + id +"]号,准备就绪...");try {countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("参赛选手[" + id +"]号,到达终点...");}}
}
结果:
参赛选手[0]号,准备就绪...
参赛选手[1]号,准备就绪...
参赛选手[2]号,准备就绪...
参赛选手[3]号,准备就绪...
参赛选手[4]号,准备就绪...
所有选手各就位.....GO!
参赛选手[1]号,到达终点...
参赛选手[3]号,到达终点...
参赛选手[0]号,到达终点...
参赛选手[2]号,到达终点...
参赛选手[4]号,到达终点...
4、示例代码
下面的示例展示了一个简单的网站爬虫,它使用 CountDownLatch 在主线程中等待其他爬虫线程完成任务。在这个例子中,我们要爬取一组网站的内容,在主线程中等待所有爬虫任务完成。
首先,我们创建一个 URLs 列表,包含多个网站 URL。
然后,我们使用 CountDownLatch 实例 latch 来跟踪待完成的爬虫任务数量。
接着,我们遍历 URL 列表,为每个 URL 创建一个新的 Crawler 线程。Crawler 类实现了 Runnable 接口,用于读取指定 URL 的网页内容。在完成任务后,它调用 latch.countDown() 方法减少计数值。
最后,在主线程中,我们调用 latch.await() 方法等待所有爬虫线程完成任务。当所有任务完成时,打印一条消息表示爬虫任务已完成。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;public class WebCrawler {private static class Crawler implements Runnable {private final String url;private final CountDownLatch latch;public Crawler(String url, CountDownLatch latch) {this.url = url;this.latch = latch;}@Overridepublic void run() {try {URL urlObject = new URL(url);BufferedReader in = new BufferedReader(new InputStreamReader(urlObject.openStream()));String inputLine;StringBuilder content = new StringBuilder();while ((inputLine = in.readLine()) != null) {content.append(inputLine);content.append("\n");}in.close();System.out.println("爬取 " + url + " 成功, 内容大小: " + content.length() + " 字符");} catch (Exception e) {System.err.println("爬取 " + url + " 失败, 原因: " + e.getMessage());} finally {latch.countDown();}}}public static void main(String[] args) throws InterruptedException {List<String> urls = new ArrayList<>();urls.add("https://github.com/");urls.add("https://stackoverflow.com/");urls.add("https://www.zhihu.com/");urls.add("https://www.reddit.com/");urls.add("https://www.linkedin.com/");CountDownLatch latch = new CountDownLatch(urls.size());System.out.println("开始爬虫任务...");for (String url : urls) {new Thread(new Crawler(url, latch)).start();}latch.await();System.out.println("所有爬虫任务都已完成!");}
}
运行结果
开始爬虫任务...
爬取 https://www.zhihu.com/ 成功, 内容大小: 37783 字符
爬取 https://github.com/ 成功, 内容大小: 227576 字符
爬取 https://stackoverflow.com/ 成功, 内容大小: 171290 字符
爬取 https://www.linkedin.com/ 成功, 内容大小: 12603 字符
爬取 https://www.reddit.com/ 失败, 原因: Read timed out
所有爬虫任务都已完成!
5、稍复杂点的示例代码
在这个例子中,我们将模拟一个简单的赛车游戏,
- 其中有一个倒计时开始。
- 一旦倒计时结束,赛车就开始比赛,
- 当所有赛车完成比赛时,主线程打印一条消息。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;public class CountDownLatchAdvancedDemo {public static void main(String[] args) throws InterruptedException {int numberOfRacers = 5;CountDownLatch startSignal = new CountDownLatch(1);CountDownLatch finishSignal = new CountDownLatch(numberOfRacers);// 创建赛车线程for (int i = 0; i < numberOfRacers; i++) {//这里虽然start,但是由于前面new了startSignal,并且实现类中await的影响会等待new Thread(new Racer(startSignal, finishSignal)).start();}// 模拟倒计时System.out.println("倒计时开始...");for (int i = 3; i > 0; i--) {System.out.println("倒计时: " + i);TimeUnit.SECONDS.sleep(1);}System.out.println("比赛开始!");startSignal.countDown(); // 启动信号// 等待所有赛车完成比赛finishSignal.await();System.out.println("所有赛车都完成了比赛!");}static class Racer implements Runnable {private CountDownLatch startSignal;private CountDownLatch finishSignal;public Racer(CountDownLatch startSignal, CountDownLatch finishSignal) {this.startSignal = startSignal;this.finishSignal = finishSignal;}@Overridepublic void run() {try {// 等待开始信号startSignal.await();// 正在比赛System.out.println(Thread.currentThread().getName() + " 开始比赛...");Thread.sleep((long) (Math.random() * 10000));System.out.println(Thread.currentThread().getName() + " 完成比赛!");} catch (InterruptedException e) {e.printStackTrace();} finally {// 完成比赛后,递减完成信号计数finishSignal.countDown();}}}
}
在这个例子中,我们创建了两个 CountDownLatch:
- 一个用于开始信号 (startSignal),
- 另一个用于完成信号 (finishSignal)。创建赛车线程时,它们都需要等待开始信号。
当倒计时结束时,调用 startSignal.countDown(),开始信号变为0,并表示比赛开始。
每个线程在模拟赛车完成比赛后,调用 finishSignal.countDown() 减少完成信号计数。
主线程使用 finishSignal.await() 等待所有赛车线程都完成比赛。当计数值变为 0 时,主线程将打印一条消息表示所有赛车都完成了比赛。
运行结果:
倒计时开始...
倒计时: 3
倒计时: 2
倒计时: 1
比赛开始!
Thread-4 开始比赛...
Thread-2 开始比赛...
Thread-0 开始比赛...
Thread-1 开始比赛...
Thread-3 开始比赛...
Thread-4 完成比赛!
Thread-1 完成比赛!
Thread-0 完成比赛!
Thread-2 完成比赛!
Thread-3 完成比赛!
所有赛车都完成了比赛!
相关文章:

CountDownLatch详解以及用法示例
一、什么是CountDownLatch CountDownLatch中count down是倒数的意思,latch则是门闩的含义。整体含义可以理解为倒数的门栓。 CountDownLatch的作用也是如此,在构造CountDownLatch(int count):的时候需要传入一个整数count,在这个…...

【http】缓存协议
✨ 专栏介绍 在当今互联网时代,计算机网络已经成为了人们生活和工作中不可或缺的一部分。而要实现计算机之间的通信和数据传输,就需要依靠各种网络协议来进行规范和约束。无论是浏览网页、发送电子邮件还是进行在线交流,都离不开各种各样的网…...

vscode中使用GitHub Copilot Chat
文章目录 一、什么是Github Copilot Chat二、安装使用三、如何使用1. 聊天功能2. 内联功能 一、什么是Github Copilot Chat GitHub Copilot Chat 由 OpenAI 的 GPT-4 大型多模态模型提供支持,能带来更准确的代码建议、解释和指导。GitHub Copilot Chat 的内联功能可…...

lvgl 双物理显示器的驱动实现
目录 一、背景 1. 要实现的功能2. lvgl 版本 二、简单粗暴的方式 理论上可以这样实现缺陷: 三、lvgl 自身机制支持 3.1 实现思路3.2 初始化缓冲区和注册显示驱动 3.2.1 复制lv_port_disp → lv_port_disp_23.2.2 修改 lv_port_disp_2 文件3.2.3 在应用层调用显示器…...

论文阅读——X-Decoder
Generalized Decoding for Pixel, Image, and Language Towards a Generalized Multi-Modal Foundation Model 1、概述 X-Decoder没有为视觉和VL任务开发统一的接口,而是建立了一个通用的解码范式,该范式可以通过采用共同的(例如语义&#…...

【Kubernetes】控制器Statefulset
Statefulset控制器 一、概念二、Statefulset资源清单文件编写技巧2.1、查看定义Statefulset资源需要的字段2.2、查看statefulset.spec字段如何定义2.3、查看statefulset的spec.template字段如何定义 三、Statefulset使用案例:部署web站点3.1、编写一个Statefulset资…...

智能优化算法应用:基于鱼鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于鱼鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于鱼鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.鱼鹰算法4.实验参数设定5.算法结果6.参考文献7.MA…...

探索 Vue3 (五) 骨架屏
骨架屏是页面的一个空白版本,通常会在页面完全渲染之前,通过一些灰色的区块大致勾勒出轮廓,待数据加载完成后,再替换成真实的内容。 目前主流 UI库 都有骨架屏,如 Element-UI、Antd 可以看到使用起来非常简单&#x…...

java取出list中的某几个属性组成一个新的集合的几种方式
我用了三种方式,1:forEach循环;2:for循环;3:stream方法 package org.springblade.test;import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors;public class Test {org.junit.jupiter.api…...

开源自托管导航页配置服务Dashy本地搭建结合内网穿透远程访问
开源自托管导航页配置服务Dashy本地搭建结合内网穿透远程访问 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 简介 Dashy 是一个开源的自托管的导航页配置服务,具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你可以将自己常用的一…...

Cloudstack多个管理服务器节点
https://docs.cloudstack.apache.org/en/4.18.0.0/adminguide/reliability.html 参考翻译: 代理上支持多个管理服务器 在具有多个管理服务器的Cloudstack环境中,可以根据算法配置代理,将其连接到哪个管理服务器。这对于内部负载均衡器或高可…...

31. Ajax
简介 AJAX 是 Asynchronous JavaScript And XML 的简称。直译为,异步的JS和XML。AJAX的实际意义是,不发生页面跳转、异步载入内容并改写页面内容的技术。AJAX也可以简单的理解为通过JS向服务器发送请求。 AJAX这门技术很早就被发明,但是直到…...

ArrayList源码学习笔记(3)
时隔两年,重新读ArrayList源码,轻松了很多,以问题的方式记录一下收获 装饰器模式 注释中提到ArrayList本身不是线程安全的,注释如下: * <p><strong>Note that this implementation is not synchronized.&…...

flutter怎么对ReorderableListView中的用于排序的控制手柄进行显示或隐藏
我在使用ReorderableListView创建可排序列表的时候,需要在编辑的时候才显示右侧的控制排序的手柄。研究了半天,配合搜索引擎,才找到正确的方案。 答案很简单,就是在它的属性当中有一个叫做:buildDefaultDragHandles的…...

python 1200例——【9】斐波那契数列
文章目录 定义求解方法1. 递归方法2. 循环方法3. 动态规划方法4. 矩阵方法总结:定义 斐波那契数列(Fibonacci sequence)是一个在自然世界中经常出现的数学序列。它是由0和1开始,然后的每个数字都是前两个数字的和。因此,斐波那契数列的前几个数字是:0, 1, 1, 2, 3, 5, 8…...

JavaScript读写T5557卡源码
本示例使用发卡器: https://item.taobao.com/item.htm?spma1z10.5-c-s.w4002-21818769070.13.48ce6f89XlQ9Vf&id675212889085 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-t…...

【数据结构】LRU缓存的简单模拟实现(leetcode力扣146LRU缓存)
文章目录 一、定义二、LRU模拟实现二、代码实现 一、定义 LRU是Least Recently Used的缩写,意思是最近最少使用,它是一种Cache替换算法。 Cache的容量有限,因此当Cache的容量用完后,而又有新的内容需要添加进来时, 就…...

基于电商场景的高并发RocketMQ实战-Commitlog基于内存的高并发写入优化、基于JVM offheap的内存读写分离机制
🌈🌈🌈🌈🌈🌈🌈🌈 【11来了】文章导读地址:点击查看文章导读! 🍁🍁🍁🍁🍁🍁dz…...

工具系列:TensorFlow决策森林_(3)使用dtreeviz可视化
文章目录 介绍设置安装 TF-DF 和 dtreeviz导入库 可视化分类树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随机森林分类器显示决策树检查叶节点统计信息决策树如何对实例进行分类特征空间划分 可视化回归树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随…...

【算法学习】斐波那契数列模型-动态规划
前言 我在算法学习过程中,针对斐波那契数列模型的动态规划的例题进行了一个整理,并且根据标准且可靠一点的动态规划解题思路进行求解类似的动归问题,来达到学习和今后复习的必要。 所谓的斐波那契数列模型,即当前状态的值等于前两…...

ES的安装和RestClient的操作
目录 初识elasticsearch 什么是elasticsearch elasticsearch的发展 Lucene的优缺点 elasticsearch的优势 倒排索引 es与mysql的概念对比 文档 索引 概念对比 架构 安装es 安装kibana 安装ik分词器 分词器 安装ik分词器 ik分词器的拓展和停用词典 操作索引库…...

访问者模式(Visitor)
访问者模式(Visitor Pattern)是一种将算法与对象结构分离的行为型设计模式。这种模式主要用于对一个由许多不同类型的对象构成的复杂对象结构(如组合结构)进行操作,而不需要对这些对象的类进行修改。 访问者模式涉及以下几个角色: 访问者(Visitor):为每一个具体元素类…...

ATTCK红队评估一
一、环境搭建 主机 ip地址 win7外网服务器(两张网卡) 外网:192.168.92.135 内网:192.168.52.143 server2003域成员主机 内网:192.168.52.141 server2008域空主机 内网:192.168.52.138 kali攻击机 …...

W5500-EVB-Pico评估版介绍
文章目录 1 概述2 板载资源2.1 硬件规格2.2 硬件规格2.3 工作条件 3 参考资料3.2 原理图3.3 尺寸图 (单位 : mm)3.4 参考例程 4 硬件协议栈优势 1 概述 W5500-EVB-Pico是基于树莓派RP2040和完全硬连线TCP/IP控制器W5500的微控制器开发板-基本上与树莓派Pico板相同,但…...

单聊和群聊
TCP协议单聊 服务端: import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Vec…...

Swift 检测 iCloud状态
Show me the code: func isICloudContainerAvailable() -> Bool {if let _ FileManager.default.ubiquityIdentityToken {return true} else {return false} }推荐一下刚上线的 App 熊猫小账本,里面有用到这篇博客讲的内容 熊猫小账本 一个简洁的记账 App&…...

使用Windi CSS(基于vue-cli)
1、先创建vue项目 利用脚手架vue-cli创建,根据需求设置vue版本、babel等,无特别要求直接用默认的vue2或vue3就行 vue create 项目名 2、运行vue项目,利用vue-cli安装Windi CSS 官网指导:Vue CLI 集成 | Windi CSS 我的经历&a…...

操作无法完成(错误 0x000006ba),Windows 11 PDF打印机无法使用解决办法
操作无法完成(错误 0x000006ba),Windows 11 PDF打印机无法使用解决办法 解决方式一 先重启一次电脑,看看是否可以解决问题。 解决方式二 重新启动 Printer Spooler 服务...

Settings中电池选项-Android13
Settings中电池选项-Android13 1、设置中界面2、电池计算2.1 充电时间计算2.1.1 BatteryUsageStats获取2.1.2 BatteryStatsImpl计算 2.2 电池剩余使用时间2.2.1 Estimate获取2.2.2 BatteryStatsImpl计算 3、电池信息来源4、命令模拟* 日志 [电池]Android 9.0 电池未充电与充电字…...

解密 Java ForEach 提前终止问题
目录 前言:场景复现分析与解决方案解决方案详解总结 前言: 你是否曾在使用 Java 8 的 forEach 迭代集合时遇到过提前终止循环的问题?在这篇博客中,我们将深入探讨这一问题,并提供多种解决方案。通过场景复现、分析源码…...