【JavaEE】——多线程常用类

 8e19eee2be5648b78d93fbff2488137b.png

阿华代码,不是逆风,就是我疯

你们的点赞收藏是我前进最大的动力!!

希望本文内容能够帮助到你!!

目录

引入:

一:Callable和FutureTask类

1:对比Runnable

2:FutureTask类

3:代码示例

示例一:Runnable

​编辑示例二:Callable

二:ReentrantLock——可重入锁

1:与synchronized的区别

(1)不会阻塞

(2)公平锁

(3)唤醒机制不同

三:Semaphore——信号量

1:P操作

2:V操作

3:PV代码示例一

4:锁功能

四:CountDownLatch

1:引入

2:代码示例


引入:

通过之前的学习,我们了解到CAS本质上是JVM替我们封装好的,我们没有办法感知到

java.util.concurrent中存放了一些我们多线程编程时常用的类

看下面的一些接口:是不是非常熟悉,我们把这个packet包简称为(JUC)

e9ca2cbd045a46b1bbf59c50a57bf57b.png

一:Callable和FutureTask类

读法:“开了波哦”    译为:调用

1:对比Runnable

Runnable提供run方法返回值为void——关注过程,不关注执行结果

Callable提供call方法返回值类型就是执行结果的类型———更关注结果

2:FutureTask类

在Callable中的call方法中完成任务的描述后,我们要想办法把这个任务加载给线程Thread

但是Thread类中并没有给出Callable的构造方法,于是我们通过FutureTask这个中间类(可以理解为加载任务的装置),作为媒介,发射给Thread

即:

Callable中描述方法——卢本伟来啦~~

FutureTask中加载任务——卢本伟已准备就绪~~

Thread中传入futureTask任务执行——卢本伟启动!!

注:

Callable和FutureTask实例化的时候<>中要写返回结果的类型哦。

futureTask.get()方法是带有阻塞功能的,如果线程还没有执行完毕,get就会被阻塞,等到线程执行完了,return的结果就会被get返回回来

3:代码示例

老问题:计算前5000个数字之和
 

看以下两段代码——用Callable类写的代码比Runnable类写的代码更加优雅~~

示例一:Runnable

package thread;public class ThreadDemon37 {private static int sum = 0;//全局变量用来保存最后的结果值public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(new Runnable() {int count = 0;//局部变量@Overridepublic void run() {for (int i = 1 ; i <= 5000 ; i++){count += i;}sum = count;}});t1.start();t1.join();System.out.println(sum);}}

c187a3ca91944a6bab8894d443652fed.png示例二:Callable

此处我们不用再引入额外的成员变量了,直接借助返回值即可

package thread;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class ThreadDemon38 {public static void main(String[] args) throws InterruptedException, ExecutionException {Callable<Integer> callable = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i <= 5000; i++) {sum += i;}return sum;}};//Thread t1 = new Thread(callable);//Thread中没有提供构造函数来传入callable//引入FutureTask类,未来要完成的任务(任务还未执行)// 相当于在Callable中确定执行的任务//在FutureTask装置中完成任务加载——卢本伟准备就绪~~~//最后引入线程——卢本伟启动!!FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread t1 = new Thread(futureTask);t1.start();t1.join();System.out.println(futureTask.get());//装置获得一下结果}
}

f9ffe1814187431eaf22c06ab0cba29c.png

补充一点:.futureTask.get()方法本身自带阻塞特性,如果Callable任务还没有执行完,是会一直等待它的返回值结果的

二:ReentrantLock——可重入锁

读音:“瑞安纯特老科” 翻译为:可重入锁

科普:ReentrantLock在很早以前是比没有发展起来的synchronized功能更加强大的,他提供了两个传统的方法lock和unlock,但是在写代码的过程中lock完后往往会忘记unlock解锁,所以一般把unlock操作放到finally里面使用

1:与synchronized的区别

(1)不会阻塞

我们知道synchronized加锁,如果线程“锁竞争”失败,会陷入阻塞等待,使用了ReentrantLodk提供了trylock方法后,如果加不上锁就会返回false,不会阻塞等待。

(2)公平锁

ReentrantLock中加锁依据是:公平锁,所有参与“加锁”的线程会被放进队列里面,按顺序进行加锁

(3)唤醒机制不同

synchronized提供wait和notify,ReentrantLock搭配Condition,功能比notify强一点

三:Semaphore——信号量

读音:“赛摸佛尔” 翻译为:信号量

科普:因为发明信号量的大佬迪杰斯特拉是个荷兰人,荷兰语的申请和释放首字母分别是P和V。实际上英语是acquire和release

1:P操作

申请一个可用资源,可用资源总数就会-1

2:V操作

释放一个可用资源,可用资源总数就会+1

打个比方:去停车场停车,现在有50个停车位,申请一个停车位(p操作),现有可用停车位为49;出来了一辆车(v操作),现有可用停车位为50;

3:PV代码示例一

package thread;import java.util.concurrent.Semaphore;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-30* Time: 10:26*/
public class ThreadDemon39 {public static void main(String[] args) throws InterruptedException {Semaphore semaphore = new Semaphore(1);//资源数限制为1个semaphore.acquire();System.out.println("p操作");semaphore.acquire();//第二次申请System.out.println("p操作");semaphore.acquire();//第三次申请System.out.println("p操作");}
}

9cf9b627497042ea9426d8388842301a.png

4:锁功能

信号量是更为广义的锁

代码示例:继续沿用解决count计数器++线程安全问题的方式

package thread;import java.util.concurrent.Semaphore;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-30* Time: 10:33*/
public class ThreadDemon40 {private static int count = 0;//引入Semaphore进行加锁private static Semaphore semaphore = new Semaphore(1);public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {try {semaphore.acquire();//加锁for (int i = 1 ; i <= 50000 ; i++){count++;}} catch (InterruptedException e) {throw new RuntimeException(e);}semaphore.release();//解锁});Thread t2 = new Thread(() ->{try {semaphore.acquire();//加锁for (int i = 1 ; i <= 50000 ; i++){count++;}} catch (InterruptedException e) {throw new RuntimeException(e);}semaphore.release();//解锁});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}

4f2381686367498d83b6d9736d662e7c.png

四:CountDownLatch

1:引入

latch(锁存器)

举个例子,现在下载软件的速度非常快,用的是多线程下载方式,比如要下载一个1G大小的软件,我们把这个任务分成10份,分给10个线程同时进行下载,最后在拼在一起,速度就会快非常多。

这个“拼”的操作,就能被CountDownLatch感知到,比我们用join要更简单方便一些

2:代码示例

package thread;import java.util.Random;
import java.util.concurrent.CountDownLatch;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-30* Time: 10:57*/
public class ThreadDemon41 {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(10);//创建10个线程Random random = new Random();int time = (random.nextInt(4)+1)*1000;//time的范围[0,4]->[1,5]->[1000,5000]for(int i = 1 ; i <= 10 ; i++){int count = i;Thread t = new Thread(() ->{try {Thread.sleep(random.nextInt(time));//产生的随机数的范围System.out.println("第" + count + "线程的任务执行完毕");latch.countDown();//告知CountDownLatch有一个任务已经执行完毕了} catch (InterruptedException e) {throw new RuntimeException(e);}});t.start();}latch.await();//如果CountDownLatch中的任务还没有执行完毕,那么CountDownLatch就会陷入阻塞等待System.out.println("所有任务都已经执行完毕了");}
}

ab344df1b057467297751a6554e614ea.png

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

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

相关文章

IT新秀系列:Go语言的兴起

Go语言&#xff08;Golang&#xff09;由谷歌于2007年发起&#xff0c;并于2009年正式开源。它的诞生背景可以追溯到互联网技术的高速发展时期。那时&#xff0c;软件开发面临着多核计算、大规模并发处理、部署和维护效率低下等挑战。作为一种新型的编程语言&#xff0c;Go主要…

秒懂Linux之线程

目录 线程概念 线程理解 地址空间&#xff08;页表&#xff0c;内存&#xff0c;虚拟地址&#xff09; 线程的控制 铺垫 线程创建 ​编辑 线程等待 线程异常 线程终止 代码 线程优点 线程缺点 线程特点 线程概念 线程是进程内部的一个执行分支&#xff0c;线程是C…

第 30 章 XML

第 30 章 XML 1.IE 中的 XML 2.DOM2 中的 XML 3.跨浏览器处理 XML 随着互联网的发展&#xff0c;Web 应用程序的丰富&#xff0c;开发人员越来越希望能够使用客户端来操作 XML 技术。而 XML 技术一度成为存储和传输结构化数据的标准。所以&#xff0c;本章就详细探讨一下 Ja…

云服务器部署k8s需要什么配置?

云服务器部署k8s需要什么配置&#xff1f;云服务器部署K8s需要至少2核CPU、4GB内存、50GBSSD存储的主节点用于管理集群&#xff0c;工作节点建议至少2核CPU、2GB内存、20GBSSD。还需安装Docker&#xff0c;选择兼容的Kubernetes版本&#xff0c;配置网络插件&#xff0c;以及确…

客运自助售票系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;乘客管理&#xff0c;司机管理&#xff0c;车票信息管理&#xff0c;订单信息管理&#xff0c;退票信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;车票信息&#…

JSON的C实现(上)

JSON的C实现&#xff08;上&#xff09; JSON的C实现&#xff08;上&#xff09;前言JSON简介JSON的C实现思路小结 JSON的C实现&#xff08;上&#xff09; 前言 JSON是众多项目中较为常见的数据交换格式&#xff0c;为不同项目、系统间的信息交换提供了一个规范化标准。JSON…

SpringBoot3+Vue3开发后台管理系统脚手架

后台管理系统脚手架 介绍 在快速迭代的软件开发世界里&#xff0c;时间就是生产力&#xff0c;效率决定成败。对于构建复杂而庞大的后台系统而言&#xff0c;一个高效、可定制的后台脚手架&#xff08;Backend Scaffold&#xff09;无疑是开发者的得力助手。 脚手架 后台脚…

从0到1深入浅出构建Nest.Js项目

Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的开发框架。它利用JavaScript 的渐进增强的能力&#xff0c;使用并完全支持 TypeScript &#xff08;仍然允许开发者使用纯 JavaScript 进行开发&#xff09;&#xff0c;并结合了 OOP &#xff08;面向对…

【Redis】知识点整理(源于javaguide)

一、什么是Redis Redis是一种开源的内存数据库&#xff0c;它支持键值存储&#xff0c;常被用作数据缓存、消息代理和队列等。它以高性能和支持多种数据结构而闻名&#xff0c;如字符串、哈希、列表、集合和有序集合。Redis也支持持久化&#xff0c;可以将数据存储在磁盘上&am…

【Docker】docker的存储

介绍 docker存储主要是涉及到3个方面&#xff1a; 第一个是容器启动时需要的镜像 镜像文件都是基于图层存储驱动来实现的&#xff0c;镜像图层都是只读层&#xff0c; 第二个是&#xff1a; 容器读写层&#xff0c; 容器启动后&#xff0c;docker会基于容器镜像的读层&…

服务器数据恢复—raid磁盘故障导致数据库文件损坏的数据恢复案例

服务器存储数据恢复环境&故障&#xff1a; 存储中有一组由3块SAS硬盘组建的raid。上层win server操作系统层面划分了3个分区&#xff0c;数据库存放在D分区&#xff0c;备份存放在E分区。 RAID中一块硬盘的指示灯亮红色&#xff0c;D分区无法识别&#xff1b;E分区可识别&a…

Python机器学习中的模型评估与优化技术

Python机器学习中的模型评估与优化技术 目录 &#x1f4ca; 模型评估与优化 1.1 交叉验证与模型评估指标 准确率、精确率、召回率、F1-score 1.2 超参数调优 网格搜索与随机搜索使用Scikit-learn的GridSearchCV与RandomizedSearchCV 1. &#x1f4ca; 模型评估与优化 1.1 …

【理论科学与实践技术】数学与经济管理中的学科与实用算法

在现代商业环境中&#xff0c;数学与经济管理的结合为企业提供了强大的决策支持。包含一些主要学科&#xff0c;包括数学基础、经济学模型、管理学及风险管理&#xff0c;相关的实用算法和这些算法在中国及全球知名企业中的实际应用。 一、数学基础 1). 发现人及著名学者 发…

开源项目 - 交通工具检测 yolo v3 物体检测 单车检测 车辆检测 飞机检测 火车检测 船只检测

开源项目 - 交通工具检测 yolo v3 物体检测 单车检测 车辆检测 飞机检测 火车检测 船只检测 开源项目地址&#xff1a;https://gitcode.net/EricLee/yolo_v3 示例&#xff1a;

物理学基础精解【44】

文章目录 球面方程一、球面方程的一般形式二、球面方程的其他形式三、球面方程的性质四、球面方程的应用五、球面方程与其他几何图形的关系 球面方程的几何意义1. 定义球面的形状和大小2. 描述球面的对称性3. 确定球面上点的位置4. 反映球面的曲率性质5. 与其他几何图形的关系6…

前端学习第二天笔记 CSS选择 盒子模型 浮动 定位 CSS3新特性 动画 媒体查询 精灵图雪碧图 字体图标

CSS学习 CSS选择器全局选择器元素选择器类选择器ID选择器合并选择器 选择器的优先级字体属性背景属性文本属性表格属性表格边框折叠边框表格文字对齐表格填充表格颜色 关系选择器后代选择器子代选择器相邻兄弟选择器通用兄弟选择器 CSS盒子模型弹性盒子模型父元素上的属性flex-…

大厂面试真题-说一下Mybatis的缓存

首先看一下原理图 Mybatis提供了两种缓存机制&#xff1a;一级缓存&#xff08;L1 Cache&#xff09;和二级缓存&#xff08;L2 Cache&#xff09;&#xff0c;旨在提高数据库查询的性能&#xff0c;减少数据库的访问次数。注意查询的顺序是先二级缓存&#xff0c;再一级缓存。…

C++入门(有C语言基础)

string类 string类初始化的方式大概有以下几种&#xff1a; string str1;string str2 "hello str2";string str3("hello str3");string str4(5, B);string str5[3] {"Xiaomi", "BYD", "XPeng"};string str6 str5[2];str…

主存储器——随机存取存储器RAM

静态RAM 双稳态触发器 一、工作特性 两种稳定状态&#xff1a; 双稳态触发器具有两个稳定的输出状态&#xff0c;通常表示为 0 和 1&#xff08;或低电平和高电平&#xff09;。这两个状态可以长期保持&#xff0c;即使在没有输入信号的情况下&#xff0c;也不会自发地改变。 例…

【分布式微服务云原生】消息队列全解析:原理、应用场景与主流MQ对比

消息队列全解析&#xff1a;原理、应用场景与主流MQ对比 摘要 在快速发展的软件架构中&#xff0c;消息队列&#xff08;MQ&#xff09;扮演着至关重要的角色。它不仅实现了系统间的异步通信&#xff0c;还提供了应用解耦、流量削峰等关键功能。本文将深入探讨消息队列的工作原…