浅谈之Java多线程
Java多线程是Java语言中一个非常重要的特性,它允许程序同时执行多个任务。通过多线程,程序可以同时处理多项任务,从而缩短程序的执行时间。另外,多线程也有助于利用多核处理器,更好地发挥计算机硬件的性能。
那我们在Java中如何去实现多线程呢?
今天我们就从最简单的的Thread
、Runnable
讲到现在比较常用的CompletableFuture
Thread
Java中通过创建Thread
类的实例来创建线程。创建线程的最简单方式是扩展Thread
类并覆盖run()
方法。在run()
方法中编写要执行的代码,然后在程序中调用start()
方法启动该线程。例如:
public class MyThread extends Thread {public void run() {// 线程要执行的代码for (int i = 0; i < 10; i++) {System.out.println("id:" + Thread.currentThread().getId() + ",name:" + Thread.currentThread().getName() + "====={" + i + "}");}}
}public static void main(String[] args) {System.out.println("start");MyThread myThread1 = new MyThread();MyThread myThread2 = new MyThread();myThread1.start();myThread2.start();System.out.println("end");
}
当然你要是嫌麻烦的话你可以直接使用匿名内部类
// 效果是一样的System.out.println("start");new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println("id:" + Thread.currentThread().getId() + ",name:" + Thread.currentThread().getName() + "{" + i + "}");}}).start();new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println("id:" + Thread.currentThread().getId() + ",name:" + Thread.currentThread().getName() + "{" + i + "}");}}).start();System.out.println("end");
这边注意千万不用使用run()
方法,这会使线程变成同步,同时如果你想让多线程的内容执行完之后再去执行之后的代码,那你可以使用join()
这个方法,它可以使该线程执行完之后再去执行下面的操作。
当然你也可以使用sleep()
让主线程睡眠一段时间,当然这个睡眠时间是主观的时间,是我们自己定的,这个方法不推荐
Runnable
此外,我们还可以使用Runnable
接口来创建线程。Runnable
接口只有一个run()
方法,在其中编写要执行的代码,然后将Runnable
对象作为参数传递给Thread
类的构造函数,并调用start()
方法启动线程。例如:
public class MyThread implements Runnable {@Overridepublic void run() {// 线程要执行的代码for (int i = 0; i < 10; i++) {System.out.println("id:" + Thread.currentThread().getId() + ",name:" + Thread.currentThread().getName() + "====={" + i + "}");}}
}
其实和Thread
差不多,只是一个实现接口,一个继承类,直接使用的话这两个没有太大的区别
不过有的地方会说Runnable
便于实现资源共享,而Thread
不能,但是经过的我的测试认为Thread
也可以实现资源共享
测试代码
public class MyThread extends Thread {private int ticket = 5;@Overridepublic void run() {// 双检索机制——保证线程的安全if (ticket > 0) {synchronized (this) {if (ticket > 0) {while (true) {System.out.println("Thread:" + Thread.currentThread().getName() + "--Thread ticket = " + ticket--);if (ticket < 0) {break;}}}}}}}public class Test {public static void main(String[] args) {MyThread myThread1 = new MyThread();new Thread(myThread1).start();new Thread(myThread1).start();new Thread(myThread1).start();new Thread(myThread1).start();new Thread(myThread1).start();new Thread(myThread1).start();}
}执行结果如下:
Thread:Thread-1--Thread ticket = 5
Thread:Thread-1--Thread ticket = 4
Thread:Thread-1--Thread ticket = 3
Thread:Thread-1--Thread ticket = 2
Thread:Thread-1--Thread ticket = 1
Thread:Thread-1--Thread ticket = 0
我们看Thread
的源代码发现:其实Thread
也就是实现了Runnable
接口,提供了更多的方法而已。所以说Thread
与Runnable
并没有什么区别。如果硬要说有什么区别的话,那就是类与接口的区别,继承与实现的区别
Callable(搭配Future)
对于子线程,我们有时候可能会有两种需求:
- 获取子线程运行结果
- 获取子线程运行状态(成功、失败、异常)
Thread
和Runnable
都不满足这两个要求,Runnable
可以获取状态但不能获取结果,于是出现了Callable
。Callable
配合Future
使用可以获得子线程执行结果。
(Future
是Java多线程中的一种异步计算方式,可以用来获取在执行任务期间进行异步计算的结果)
public class MyThread implements Callable<Integer> {private Integer number;public Integer getNumber(){return number;}public MyThread (Integer number) {this.number = number;}@Overridepublic Integer call() throws Exception {int result = 0;for (int i = 0; i < number; i++) {result ++;System.out.println("id:" + Thread.currentThread().getId() + ",name:" + Thread.currentThread().getName() + "====={" + result + "}");}return result;}
}public static void main(String[] args) throws Exception {System.out.println("start");MyThread myThread1= new MyThread (10);MyThread myThread2= new MyThread (15);//使用Executors工厂类创建一个简单的线程池(线程数:2)ExecutorService executor = Executors.newFixedThreadPool(2);// 将任务提交给线程池 Future<Integer> submit1 = executor.submit(myThread1);Future<Integer> submit2 = executor.submit(myThread2);// 获取任务的执行结果System.err.println(submit1.get());System.err.println(submit2.get());executor.shutdown();System.out.println("end");}
在这个例子中,我们实现了MyThread
类,它实现了Callable
接口,并重写了call()
方法。在call()
方法中,我们模拟了一个长时间运行的任务,并返回一个计算结果作为执行结果。在main方法中,我们首先创建了一个固定线程数的线程池ExecutorService
,然后将MyThread
的实例传入submit
方法来提交任务,并得到一个Future
类型的对象。通过调用该对象的get()
方法,我们可以获取任务的执行结果。最后,我们关闭了线程池。
需要注意的是,由于调用Future
的get()
方法是阻塞的,所以我们可能需要对其进行try-catch
处理。此外,在完成任务后,我们必须关闭线程池以释放资源。
这是一个简单的使用Callable
的示例,通过组合多个Future
对象可以实现更复杂的并发计算。
Future
当然 Future
也可以进行单独使用。
在使用Future
时,可以调用get()
方法来阻塞等待任务执行完毕并获取计算结果;也可以调用isDone()
方法来判断任务是否执行完毕;如果任务执行过程中发生异常,可以通过调用get()
方法获取异常信息
public static void main(String[] args) throws Exception {System.out.println("start");ExecutorService executor = Executors.newFixedThreadPool(2);Future future1 = executor.submit(() -> {int result = 0;for (int i = 0; i < number; i++) {result ++;System.out.println("id:" + Thread.currentThread().getId() + ",name:" + Thread.currentThread().getName() + "====={" + result + "}");}return result;});Future future2 = executor.submit(() -> {int result = 0;for (int i = 0; i < number; i++) {result ++;System.out.println("id:" + Thread.currentThread().getId() + ",name:" + Thread.currentThread().getName() + "====={" + result + "}");}return result;});String result1 = (String) future1.get();String result2 = (String) future2.get();System.out.println(result1);System.out.println(result2);executor.shutdown();System.out.println("end");}
其实和上一个方法是一样的,只不过是这边把call()
方法中的业务逻辑冗余到了主代码中,耦合性更高了,如果只是一些简单的代码可以使用,复杂的话还是建议搭配callable
一起使用比较好
CompletableFuture
CompletableFuture
是Java 8引入的一个非常有用的功能,它可以让我们更轻松地处理异步操作,特别是当这些操作涉及到多个阶段时。
CompletableFuture
继承自 Future
接口,可以在计算完成后获取计算结果,因此它也具备了 Future
的特性。除此之外,它还提供了一些其他的特性:
- 异步执行和串行执行功能
- 任务执行完毕后可以触发观察者机制
- 可以将两个任务组合到一起执行等,处理更加复杂的异步场景。
现在开发来说使用较为复杂的逻辑普遍会使用CompletableFuture
创建
CompletableFuture
我们可以使用runAsync()
方法直接去异步执行
CompletableFuture.runAsync(() -> {// 在这里执行一些耗时的操作});
异步处理
CompletableFuture
的结果
我们可以使用CompletableFuture
的静态方法supplyAsync()
创建一个异步执行的CompletableFuture
,并提供一个lambda
表达式作为其计算发生器:
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {// 在这里执行一些耗时的操作return "some result";
});completableFuture.thenAccept(result -> {System.out.println("Got result: " + result);
});
// 这里可以继续执行其他任务,completableFuture将在后台继续执行并在完成后触发回调函数。
操作两个或多个
CompletableFuture
如果我们需要等待多个CompletableFuture
都完成后执行某些任务,那么我们可以使用CompletableFuture
的静态方法allOf()
或anyOf()
:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {// 在这里执行一些耗时的操作return "Result of future 1";
});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {// 在这里执行一些耗时的操作return "Result of future 2";
});CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);allFutures.thenRun(() -> {//这边join和get方法都可以 只是抛出异常的区别String result1 = future1.join();String result2 = future2.join();System.out.println("Got both results: " + result1 + " and " + result2);
});
CompletableFuture
默认使用的是ForkJoinPool
线程池,如果你想自己定义线程池的话可以使用Executors
直接创建一个,但是Executors
是一个工厂类,提供了一些静态方法用于创建线程池,而不是一个线程池本身,因此无法设置线程的详细参数例如:核心线程数,最大线程数,拒绝策略等。如果需要设置这些参数,应该使用ThreadPoolExecutor
类来手动创建线程池
/*** public ThreadPoolExecutor(int corePoolSize,* int maximumPoolSize,* long keepAliveTime,* TimeUnit unit,* BlockingQueue<Runnable> workQueue,* ThreadFactory threadFactory,* RejectedExecutionHandler handler) {}* 1. corePoolSize:核心线程数;当提交的任务数大于 corePoolSize 时,线程池会自动扩容。** 2. maximumPoolSize:线程池最大线程数;当活动线程数达到该值,并且 workQueue 队列已满,则执行拒绝策略。** 3. keepAliveTime:线程空闲超时时间,超过该时间则进行回收。** 4. unit:keepAliveTime 的时间单位。** 5. workQueue:任务阻塞队列,用于存储提交但尚未执行的任务。** 6. threadFactory:线程工厂,用于创建线程。** 7. handler:拒绝策略,当线程数量已经达到 maximumPoolSize 并且队列已满时,采取的策略。*/ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,10,10,TimeUnit.SECONDS,new LinkedBlockingQueue(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
在
springboot
中有个方法也用的很频繁——@async
,只需要在方法上加上这个注解并在启动类上加上@Enableasync
就可以直接实现多线程异常操作,不过这个多线程的方法和上面讲的还是有些区别的,@async
是调用方法的时候进行多线程异步操作,但是方法中的业务逻辑还是同步的,所以正常可以搭配ComplatableFuture
一起使用(当然也可以吧中间的业务逻辑提取出方法再加个@async
哈哈哈哈 都可以的)
Java的多线程机制是Java编程中不可或缺的一部分,了解和熟悉Java多线程编程能力将极大地提升程序员的工作效率和编程水平。
相关文章:
浅谈之Java多线程
Java多线程是Java语言中一个非常重要的特性,它允许程序同时执行多个任务。通过多线程,程序可以同时处理多项任务,从而缩短程序的执行时间。另外,多线程也有助于利用多核处理器,更好地发挥计算机硬件的性能。 那我们在…...

【Vue3学习笔记1】一个清单应用帮你入门Vue.js
Vue 目前已经是国内最流⾏的前端框架之⼀,Vue 3 带来的诸多优化更是让前端圈迎来了新的潮流,比如: 基于 Proxy 的全新响应式实现; Composition API <script setup> 组织代码的更优方式; 更有料的 TypeScript 支…...
go破冰之旅·8·go函数基本实践及各种玩法
一次5-10分钟即可搞定,以干货效率的学习方式带你更直观的玩转各种玩法! 行文不易,一字一句纯手打创造,倾注了不少精力,感谢支持。 目录 什么是函数?有哪些元素? 函数参数、返回值 小程序&…...

Qt - 从零到壹的 打地鼠 游戏
❤️🔥欢迎收看西北风的blog,好男人就是我,我就是西北风。✨ Gitee 地址 W_A_Mole NTC_jason/cc语言 - 码云 - 开源中国 (gitee.com) 目录 🟥一:创建一个主窗体 🟣二.:添加主窗口背景图片…...

代码自动发布系统
之前是jenkins发现gitlab代码更新了就自动获取直接部署到服务器 现在是jenkins自动获取Code之后打包成镜像上传到仓库然后通知docker去拉取更新的镜像 分析 旧∶ 代码发布环境提前准备,以主机为颗粒度静态 新: 代码发布环境多套,以容器为颗粒度编译 …...
qemu-基础篇(一)——安装
文章目录 env安装查看版本查看支持的开发板查看支持的CPU的型号 env ubuntu 安装 sudo apt-get install qemu sudo apt-get install qemu-system-arm sudo apt-get install qemu-system查看版本 qemu-img -V qemu-system-arm --version qemu-system-aarch64 --version返回结…...

从根本上理解Synchronized的加锁过程
作为一个Java开发,对于Synchronized这个关键字并不会陌生,无论是并发编程,还是与面试官对线,Synchronized可以说是必不可少。 在JDK1.6之前,都认为Synchronized是一个非常笨重的锁,就是在之前的《谈谈Java…...

CANOE入门到精通——CANOE系列教程记录1 第一个仿真工程
本系列以初学者角度记录学习CANOE,以《CANoe开发从入门到精通》参考学习,CANoe16 demo版就可以进行学习 概念 CANoe是一种用于开发、测试和分析汽车电子系统的软件工具。它通过在不同层次上模拟汽车电子系统中的不同部件,如ECU、总线和传感…...

JavaEE——单例模式
文章目录 一、介绍什么是单例模式二、饿汉模式三、懒汉模式四、讨论两种模式的线程安全问题 一、介绍什么是单例模式 在介绍单例模式之前,我们得先明确一个名词设计模式。 所谓设计模式其实不难理解,就是在计算机这个圈子中,呢些大佬们为了…...
关于数据倾斜
1、数据倾斜表现 1.1 hadoop中的数据倾斜表现 有一个多几个Reduce卡住,卡在99.99%,一直不能结束。各种container报错OOM异常的Reducer读写的数据量极大,至少远远超过其它正常的Reducer伴随着数据倾斜,会出现任务被kill等各种诡异…...
Shell第一次作业
要求: 1、判断当前磁盘剩余空间是否有20G,如果小于20G,则将报警邮件发送给管理员,每天检查一次磁盘剩余空间。 2、判断web服务是否运行(1、查看进程的方式判断该程序是否运行,2、通过查看端口的方式判断…...

实例解读nn.AdaptiveAvgPool2d((1, 1))
nn.AdaptiveAvgPool2d((1, 1))在PyTorch中创建一个AdaptiveAvgPool2d类的实例。该类在输入张量上执行2D自适应平均池化。 自适应平均池化是一种池化操作,它计算每个输入子区域的平均值并产生一个指定大小的输出张量。子区域的大小是根据输入张量的大小和输出张量的…...

泛型编程 之模板(template)
C另一种编程思想称为 泛型编程,主要利用的技术就是模板 目录 C另一种编程思想称为 泛型编程,主要利用的技术就是模板 一、概念 二、函数模板 1、语法与使用: 2、函数模板注意事项 3、普通函数与函数模板的区别 4、普通函数与函数模板的调用规…...

用ChatGPT问DotNet的相关问题,发现DotNet工程师的前景还不错
本人最近费了九牛二虎之力注册了一个ChatGPT账号,现在就给大家分享一下,问一下关于.NET的问题,看看ChatGPT的AI功能具体如何? 一、C#跟其它语言比较的优势 回答: C#是一门编程语言,它是为 Microsoft 的 …...
LeetCode_字符串_简单_415.字符串相加
目录 1.题目2.思路3.代码实现(Java) 1.题目 给定两个字符串形式的非负整数 num1 和num2,计算它们的和并同样以字符串形式返回。 你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将…...

Insix:面向真实的生成数据增强,用于Nuclei实例分割
文章目录 InsMix: Towards Realistic Generative Data Augmentation for Nuclei Instance Segmentation摘要本文方法数据增强方法具有形态学约束的前景增强提高鲁棒性的背景扰动 实验结果 InsMix: Towards Realistic Generative Data Augmentation for Nuclei Instance Segment…...

CleanMyMac X4.13.2最新版下载
现在cleanmymac x4.13.2中文版是大家首选的优秀mac清理软件。CleanMyMac集合了多种功能,几乎可以满足用户所有的清洁需求。它不仅包含各种清理功能,还具有卸载、维护、扩展、碎纸机等实用功能,可同时替代多种工具。它可以清理、优化、维护和监…...
机器学习算法原理:详细介绍各种机器学习算法的原理、优缺点和适用场景
目录 引言 二、线性回归 三、逻辑回归 四、支持向量机 五、决策树 六、随机森林 七、K-均值聚类 八、主成分分析(PCA) 九、K近邻算法 十、朴素贝叶斯分类器 十一、神经网络 十二、AdaBoost 十三、梯度提升树(Gradient Boosting T…...
Spring Security 6.0系列【32】授权服务器篇之默认过滤器
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.0.4 本系列Spring Security 版本 6.0.2 本系列Spring Authorization Server 版本 1.0.2 源码地址:https://gitee.com/pearl-organization/study-spring-security-demo 文章目录 前言1. OAuth2Authorizati…...

.NET中比肩System.Text.Json序列化反序列化组件MessagePack
简介 官方定义:MessagePack是一种高效的二进制序列化格式。它允许您像JSON一样在多个语言之间交换数据。但是它更快并且更小。 MessagePack是一种开源的序列化反序列化组件,可支持JAVA,C#等主流语言。在 C# 中使用 MessagePack,…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...