线程的深入学习(二)

news2024/11/28 12:44:05

前言

上一篇讲了线程池的相关知识,这篇文章主要讲解一个
1.并发工具类如CountDownLatch、CyclicBarrier等。
2.线程安全和并发集合:
3.学习如何使用Java提供的线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList等。

并发工具类

  1. CountDownLatch(倒计数器):有两个常用场景
    1.协调子线程结束动作,等待所有子线程运行结束。CountDownLatch允许一个或多个线程等待其他线程完成操作。
    例如,我们很多人喜欢玩的王者荣耀,开黑的时候,得等所有人都上线之后,才能开打
public static void main(String[] args) throws InterruptedException
{ CountDownLatch countDownLatch = new CountDownLatch(5);
Thread 大乔 = new Thread(countDownLatch::countDown);
 Thread 兰陵王 = new Thread(countDownLatch::countDown);
 Thread 安其拉 = new Thread(countDownLatch::countDown);
 Thread 哪吒 = new Thread(countDownLatch::countDown);
  Thread= new Thread(() -> {
try {
// 稍等,上个卫生间,马上到... Thread.sleep(1500);
countDownLatch.countDown();
} catch (InterruptedException ignored) {}
});
大乔.start();
兰陵王.start();
安其拉.start();
哪吒.start();.start(); countDownLatch.await();
System.out.println("所有玩家已经就位!");
}
  1. 协调线程开始动作,统一各线程开始的时机。
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
Thread 大乔 = new Thread(() -> waitToFight(countDownLatch)); 
Thread 兰陵王 = new Thread(() - > waitToFight(countDownLatch));
 Thread 安其拉 = new Thread(() ->waitToFight(countDownLatch)); 
Thread 哪吒 = new Thread(() -> waitToFight(countDownLatch));
Thread= new Thread(() -> waitToFight(countDownLatch));
大乔.start();
兰陵王.start();
安其拉.start();
哪吒.start();.start(); Thread.sleep(1000);
countDownLatch.countDown();
System.out.println("敌方还有5秒达到战场,全军出击!");
}

private static void waitToFight(CountDownLatch countDownLatch) {
try {
countDownLatch.await(); // 在此等待信号再继续
System.out.println("收到,发起进攻!");
} catch (InterruptedException e)
{ e.printStackTrace();
}
}

countdownlatch核心方法:

  • await():等待latch降为0
  • boolean await(Long Time,TImeUnit unit) : 等待latch降为0,但是设置了超时时间,毕竟不能为了某人等到永久。
  • counDown():latch数量减一
  • getCount():获取当前数量

CyclicBarrier同步屏障

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情就是让一组线程到达一个屏障(也可叫做同步点)时候被阻塞,直到最后一个线程到达屏障的时候,屏障开门,所有的被拦截的线程才会被放行。
和countdownlatch类似,都有协调多线程的结束动作。
不同:countdownlatch的使用是一次性的,无法重复利用,而cyclicBarrier可以重复利用。
最核心的方法是await:如果当前的一个线程不是第一个到达的话,它将会进入等待,直到其他线程都到达,除非发生了被中断,屏障被破除,被拆除,屏障重设等。
在这里插入图片描述

countdownlatch和cyclicBarrier区别点

  • countdownlatch是一次性的,而cyclicBarrier则可以设置多次的屏障,实现重复利用。
  • countdownlatch中的各个子线程不可以等待其他线程执行完毕,只能执行自己的任务,而CyclicBarrier可以等待其他的线程。
    |CyclicBarrier| CountDownLatch|
CyclicBarrierCountDownLatch
CyclicBarrier是可以重复利用的,其中的线程可以等待所有的线程完成任务,这是屏障会拆除,并可以选择性的做一些特定的动作是一次性的,不同的线程在同一个计数器上工作,直到线程为0
是面向线程数的是面向任务数的
再使用 CyclicBarrier时候,必须再构造器中指定参加的线程数,这些线程必须实现await()方法使用Countdownlatch必须要指定任务数,但是这些任务由那些线程完成无关紧要
CyclicBarrier可以再所有线程释放后重复使用COuntdownlatch在计数为0后就不能再使用了
再CyclicBarrier中,如果某个线程遇到中断,超时等问题,那么处于await的线程都会出现问题再COuntdownlatch中一个线程出现问题,不会影响其他线程。

Semaphore(信号量)

semaphore信号量是用来控制同时访问特定的资源的线程数量,通过协调各个线程,以保证合理的使用公共资源。
在这里插入图片描述

一个Semaphore的用途:它可以用于做流量控制,特别是公用资源有限的应用场景,比如数据库连接。

public class SemaphoreTest {
private static final int THREAD_COUNT = 30;
private static ExecutorService threadPool =
Executors.newFixedThreadPool(THREAD_COUNT);
private static Semaphore s = new Semaphore(10);
public static void main(String[] args) {
				for (int i = 0; i < THREAD_COUNT; i++)
				{ threadPool.execute(new Runnable() {
				@Override
				public void run()
				{ try {
						s.acquire();
						System.out.println("save data");
						s.release();
				} catch (InterruptedException e) {
				}
				}
});
public class ExchangerTest {
private static final Exchanger<String> exgr = new Exchanger<String>();
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
				threadPool.execute(new Runnable()
				{ @Override
				public void run()
				{ try {
				String A = "银行流水A"; // A录入银行流水数据
				exgr.exchange(A);
				}
				threadPool.shutdown();
}
}

在代码中,虽然有30个线程在执行,但是只允许10个并发执行。Semaphore的构造方法 Semaphoreint permits)接受一
个整型的数字,表示可用的许可证数量。 Semaphore10) 表示允许10个线程获取许可证,也就是最大并发数是10Semaphore的用法也很简单,首先线程使用 Semaphoreacquire()方法获取一个许可 证,使用完之后调用release()方
法归还许可证。还可以用tryAcquire()方法尝试获取许可证。

Exchanger交换者

是一个用于线程之间协调协作的工具类,Exchanger用于线程之间的数据交换,他提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。

这两个线程通过 exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。
Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时候会交换两人的数据,并使用交叉规
则得出2个交配结果。Exchanger也可以用于校对工作,比如我们需要将纸制银行流水通过人工的方式录入成电子银行
流水,为了避免错误,采用AB岗两人进行录入,录入到Excel之后,系统需要加载这两个Excel,并对两个 Excel数据进
行校对,看看是否录入一致

qw

public class ExchangerTest {
private static final Exchanger<String> exgr = new Exchanger<String>();
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
threadPool.execute(new Runnable()
{ @Override
public void run()
{ try {
String A = "银行流水A"; // A录入银行流水数据
exgr.exchange(A);
} catch (InterruptedException e) {
}
}
});
threadPool.execute(new Runnable() { @Override
public void run() { try {
String B = "银行流水B"; // B录入银行流水数据
String A = exgr.exchange("B");
System.out.println("A和B数据是否一致:" + A.equals(B) + ",A录入的是:" + A + ",B录入是:" + B);
} catch (InterruptedException e) {
}
}
});
threadPool.shutdown();
}
}

假如两个线程有一个没有执行exchange()方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以使用
exchange(V x, long timeOut, TimeUnit unit)设置最大等待时长。

总结

本篇主要就是讲了两个并发工具类。Countdownlatch倒计数器和CyclicBarrier同步屏障,以及一个semaphore信号量。

ps:如果可以一键三连,给加点动力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1356823.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java练习题之String方法运用

应用知识点&#xff1a;​​​​​​String类 1&#xff1a;(String 类)仔细阅读以下代码段&#xff1a; String s "hello"; String t"hello"; char[] c {h,e,l,l,o}; 2&#xff1a;下列选项输出结果为false 的语句是() System.out.println( s.euqals( t…

线段树基础(下)

线段树二分 对序列进行二分的操作&#xff0c;可能使用线段树二分进行优化。 一些序列上最左/最右位置问题可以二分解决&#xff0c;同时需要使用线段树进行查询。时间复杂度通常是 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n)&#xff0c;可以尝试使用线段树二分的技巧将其优…

机器学习(四) -- 模型评估(2)

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理&#xff08;1-3&#xff09; 机器学习&#xff08;三&#xff09; -- 特征工程&#xff08;1-2&#xff09; 机器学习&#xff08;四&#xff09; -- 模型评估…

B端产品经理学习-对用户进行需求挖掘

目录&#xff1a; 用户需求挖掘的方法 举例&#xff1a;汽车销售系统的用户访谈-前期准备 用户调研提纲 预约用户做访谈 用户访谈注意点 我们对于干系人做完调研之后需要对用户进行调研&#xff1b;在C端产品常见的用户调研方式外&#xff0c;对B端产品仍然适用的 用户需…

6.1810: Operating System Engineering 2023 <Lab6: Multithreading>

一、本节任务 二、要点 2.1 锁&#xff08;Locking&#xff09; 在多 CPU 或者单 CPU 多线程并发的场景中&#xff0c;对临界资源&#xff08;或者说共享资源&#xff09;的访问如果不加以限制&#xff0c;可能会引发一些严重的问题&#xff0c;比如当两个线程同时对一个共享…

Python初探:从零开始的编程奇妙之旅

一、Python是什么 Python是一门多用途的高级编程语言&#xff0c;以其简洁、易读的语法而脱颖而出。在深度学习领域&#xff0c;Python扮演着至关重要的角色。其丰富的科学计算库&#xff08;如NumPy、Pandas、Matplotlib&#xff09;和强大的深度学习框架&#xff08;如Tenso…

jmeter参数化的三种方式

1.用户定义变量 使用变量&#xff1a; ${变量名} 这个变量是全局变量&#xff0c;也就是在下面子节点中都可以使用&#xff1b; 使用场景&#xff1a;两个账号分别有不同的权限&#xff0c;A经办&#xff0c;B审核。等。。。 2.CSV数据文件设置 3.函数

案例071:基于微信小程序的汽车预约维修系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

jupyter更改默认路径到其它的目录或者到其它的盘 比如D盘

1.打开终端 输入jupyter notebook --generate-config 如下 2.在C:\Users\mb5958\.jupyter路径下 3.用记事本打开它&#xff0c;搜索directory 4.在你想要的路径下新建一个文件夹&#xff0c;如‘D:\jupyterFile’&#xff0c;然后将路径名放在c.NotebookApp.notebook_dir"…

卷麻了,00后测试用例写的比我还好,简直无地自容...........

经常看到无论是刚入职场的新人&#xff0c;还是工作了一段时间的老人&#xff0c;都会对编写测试用例感到困扰&#xff1f;例如&#xff1a; 如何编写测试用例&#xff1f; 作为一个测试新人&#xff0c;刚开始接触测试&#xff0c;对于怎么写测试用例很是头疼&#xff0c;无法…

【PCB专题】Allegro封装更新焊盘

在PCB封装的绘制中&#xff0c;有时会出现需要更新焊盘的情况。比如在制作封装的过程中发现焊盘做的不对而使用PAD_Designer重新更新了焊盘。 那在PCB中如何更新已经修改过的焊盘呢&#xff1f; 打开封装&#xff0c;选择Tools->Padstack->Refresh... 选择Refresh all …

让 sdk 包静默升级的 SAO 操作,你见过几种?

拓展阅读 让 sdk 包静默升级的 SAO 操作&#xff0c;你见过几种&#xff1f; 业务背景 有时候为业务方提供了基础的 sdk 包&#xff0c;为了保证稳定性&#xff0c;一般都是 release 包。 但是每一次升级都非常痛苦&#xff0c;也不可能写一个一步到位的 jar 包&#xff0c…

javascript 常见工具函数(三)

21.克隆数组的几种方法&#xff1a; &#xff08;1&#xff09;slice方法&#xff1a; let arr [1,2,3,4] let arr1 arr.slice() //或者是 let arr1 arr.slice(0) arr[0] 6 console.log(arr) // [6, 2, 3, 4] console.log(arr1) // [1, 2, 3, 4] &#xff08;2&…

Android Jetpack学习系列——Navigation

写在前面 Google在2018年就推出了Jetpack组件库&#xff0c;但是直到今天我才给重视起来&#xff0c;这真的不得不说是一件让人遗憾的事。过去几年的空闲时间里&#xff0c;我一直在尝试做一套自己的组件库&#xff0c;帮助自己快速开发&#xff0c;虽然也听说过Jetpack&#…

Stable Diffusion模型概述

Stable Diffusion 1. Stable Diffusion能做什么&#xff1f;2. 扩散模型2.1 正向扩散2.2 反向扩散 3. 训练如何进行3.1 反向扩散3.2 Stable Diffusion模型3.3 潜在扩散模型3.4 变分自动编码器3.5 图像分辨率3.6 图像放大 4. 为什么潜在空间是可能的&#xff1f;4.1 在潜在空间中…

【智慧地球】星图地球 | 星图地球超算数据工场

当前空天信息处理涉及并发并行的大量计算问题&#xff0c;需要高性能计算、智能计算联合调度&#xff0c;以此来实现多算力融合&#xff1b;而我国算力产业规模快速增长&#xff0c;超算算力资源正需要以任务驱动来统筹。 基于此&#xff0c;中科星图与郑州中心展开紧密合作&a…

Qt学习_17_一些关于QTableWidget的记录

1 QTableWidget::clear() 程序异常退出 近日&#xff0c;项目中使用到QTableWidget&#xff0c;遇到一个问题&#xff0c;项目需要清空这个表格&#xff0c;但是无论调用clear()&#xff0c;clearContents()&#xff0c;程序都报&#xff1a;程序异常退出。 而且项目程序还比较…

OpenVINS学习5——VioManager.cpp/h学习与注释

前言 之前又看到说VioManager.cpp/h是OpenVINS中的核心程序&#xff0c;这次就看看这里面都写了啥&#xff0c;整体架构什么样&#xff0c;有哪些函数功能。具体介绍&#xff1a; VioManager类 整体分析 VioManager类包含 MSCKF 工作所需的状态和其他算法。我们将测量结果输…

二维码地址门牌管理系统:物业管理的未来趋势

文章目录 前言一、数字化管理与便捷服务二、身份认证与安全保障三、业主便利与贴心服务四、未来发展趋势 前言 在数字化时代&#xff0c;物业管理面临着不断增加的挑战。为了提高管理效率、服务业主&#xff0c;二维码门牌管理系统应运而生。本文将探讨这一新型管理方式&#…

【OpenBMC】的内部README 模板

OpenBMC 本项目的AST2500分支核心代码的机型是ast2500-default&#xff0c;克隆代码后进入编译环境的命令为&#xff1a; source setup ast2500-default 一、源码下载、配置以及编译 重要&#xff1a;请参阅confluence 详细步骤 二、代码使用方法 目前所有自定义修改的代码…