多线程篇-5--线程分类(线程类型,springboot中常见线程类型,异步任务线程)
常见的线程类型包括用户线程(User Threads)、守护线程(Daemon Threads)、主线程(Main Thread)、工作线程(Worker Threads)和线程池中的线程。
一、用户线程(User Threads)
特点:
- 用户线程是普通的Java线程,通常由程序员显式创建。
- 用户线程在程序运行期间一直存在,直到它们完成任务或程序终止。
代码示例:
public class UserThreadExample {public static void main(String[] args) {Thread userThread = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("User thread running: " + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});userThread.start();}
}
2、守护线程(Daemon Threads)
特点:
- 守护线程是在后台运行的线程,它们通常用于为其他线程提供服务。
- 当所有用户线程都结束时,JVM会自动终止守护线程并退出。(即使守护线程没有执行完任务,也会被JVM强制退出,所以主要业务一定不能放在守护线程中执行)
- 守护线程通常用于执行一些辅助任务,如垃圾回收、日志记录等。
代码示例:
public class DaemonThreadExample {public static void main(String[] args) {Thread daemonThread = new Thread(() -> {while (true) {System.out.println("Daemon thread running...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});daemonThread.setDaemon(true); // 设置为守护线程,就这一句就够了daemonThread.start();// 主线程休眠一段时间后结束try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}
}
解释:
- 创建一个新的线程daemonThread,并将其设置为守护线程。
- 守护线程无限循环运行,每秒打印一条消息。
- 主线程休眠5秒后结束,此时JVM会自动终止,守护线程也会被终止。
3、主线程(Main Thread)
特点:
- 主线程是每个Java应用程序的入口点,它是JVM在启动时自动创建的第一个线程。
- 主线程负责执行main方法中的代码。
- 当主线程结束时,如果还有其他用户线程在运行,JVM会继续运行这些线程。
代码示例:
public class MainThreadExample {public static void main(String[] args) {System.out.println("Main thread started");Thread userThread = new Thread(() -> {System.out.println("User thread running...");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}});userThread.start(); // 用户线程启动,实际上就是主线程干的事情System.out.println("Main thread ending");}
}
解释:
- 主线程执行main方法中的代码。
- 创建并启动一个用户线程userThread。
- 主线程在启动用户线程后继续执行打印,之后就结束了。
- 用户线程会继续运行,直到完成任务。
4、工作线程(Worker Threads)
特点:
- 工作线程通常用于执行具体的任务,它们可以是用户线程或守护线程。
- 工作线程通常由线程池管理,用于处理任务队列中的任务。
- 工作线程可以提高应用程序的并发性和性能。
代码示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class WorkerThreadExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2); // 创建固定大小的线程池for (int i = 0; i < 5; i++) {int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown(); // 关闭线程池}
}
解释:
- 创建一个固定大小为2的线程池executor。
- 提交5个任务到线程池,每个任务在执行时会打印任务ID和当前线程名称。
- 调用shutdown方法关闭线程池,等待所有任务完成。
5、线程池中的线程
特点:
- 线程池中的线程是由线程池管理的,它们可以重复使用,减少了创建和销毁线程的开销。
- 线程池可以控制并发线程的数量,避免过多的线程消耗系统资源。
- 线程池通常用于处理大量的短期任务。
代码示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newCachedThreadPool(); // 创建可缓存线程池for (int i = 0; i < 10; i++) {int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown(); // 关闭线程池}
}
解释:
- 创建一个可缓存线程池executor,它会根据需要创建新的线程。
- 提交10个任务到线程池,每个任务在执行时会打印任务ID和当前线程名称。
- 调用shutdown方法关闭线程池,等待所有任务完成。
6、线程分类总结
(1)、用户线程:普通的Java线程,由程序员显式创建。
(2)、守护线程:后台线程,用于提供服务,当所有用户线程结束时自动终止。
(3)、主线程:JVM自动创建的第一个线程,执行main方法中的代码。
(4)、工作线程:用于执行具体任务的线程,通常由线程池管理。
(5)、线程池中的线程:由线程池管理的线程,可以重复使用,减少开销。
7、springboot常见线程类型
(1)、主线程(Main Thread)
1、概述
- 这是Spring Boot应用启动时由JVM创建的第一个线程。
- 主线程负责启动Spring Boot应用,加载配置,初始化Spring容器等。
2、创建时机
- 应用启动时,由JVM自动创建。
代码示例
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
(2)、Tomcat/NIO线程(接受客户端请求用)
1、概述
- 如果你的Spring Boot应用使用了嵌入式的Tomcat服务器,Tomcat会创建多个线程来处理HTTP请求。
- 这些线程通常是NIO线程(非阻塞线程,可异步),负责接收客户端请求并处理响应。
2、创建时机
- 当Spring Boot应用启动并初始化嵌入式Tomcat服务器时。
配置文件示例
无需编码,仅配置即可,不配置也可以会有默认配置。
server:port: 8080tomcat:max-threads: 200 # 最大线程数min-spare-threads: 10 # 最小空闲线程数
(3)、定时任务线程(Scheduled Tasks)
1、概述
- 如果你在Spring Boot应用中使用了定时任务(如@Scheduled注解),Spring Boot会创建一个或多个线程来执行这些定时任务。
- 这些线程通常由TaskScheduler管理。
2、创建时机
- 当Spring Boot应用启动并初始化定时任务时。
代码示例
@Configuration
@EnableScheduling
public class SchedulerConfig {
}@Component
public class ScheduledTasks {@Scheduled(fixedRate = 5000) // 自动创建定时任务线程监听并执行public void performTask() {System.out.println("Executing scheduled task at " + LocalDateTime.now());}
}
(4)、异步任务线程(Async Tasks)
1、概述
- 如果你在Spring Boot应用中使用了异步方法(如@Async注解),Spring Boot会创建一个或多个线程来执行这些异步任务。
- 这些线程通常由TaskExecutor管理。
这个在附录中在详细说明。
(5)、自定义线程
1、概述
- 你可以在Spring Boot应用中手动创建和管理线程,例如通过实现Runnable接口或继承Thread类。
2、创建时机
- 在你需要的时候手动创建。
代码示例
@Component
public class CustomThreadExample {@PostConstructpublic void startCustomThread() {Thread customThread = new Thread(() -> {while (true) {System.out.println("Custom thread running at " + LocalDateTime.now());try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}});customThread.start();}
}
附录:
异步任务线程(Async Tasks)
1、概述
- 如果你在Spring Boot应用中使用了异步方法(如@Async注解),Spring Boot会创建一个或多个线程来执行这些异步任务,主线程不会阻塞会继续执行后面的代码。
- 这些线程通常由TaskExecutor管理。
- 使用异步任务,使用@EnableAsync开启后(主方法等配置入口),在需要的方法上添加@Async注解即可。
2、异步任务线程的作用
(1)、提高响应性
- 异步任务线程可以在后台执行耗时的操作,而不阻塞主线程或请求处理线程。这样,主线程可以继续处理其他请求,提高系统的整体响应性。
(2)、优化资源利用
- 对于耗时较长的任务,如果使用同步方式处理,可能会占用宝贵的线程资源,导致其他任务无法及时处理。异步任务线程可以将这些任务移到后台执行,释放主线程资源。
(3)、并发处理
- 异步任务线程可以并行处理多个任务,提高系统的并发处理能力。这对于需要处理大量并发请求的应用尤其重要。
3、异步任务特点
(1)、异步任务线程:异步任务在单独的线程中执行,不会阻塞主线程。
(2)、立即返回:异步方法调用会立即返回一个CompletableFuture对象,主线程可以继续执行其他任务。
(3)、回调机制:使用thenAccept等方法注册回调函数,这些回调函数在异步任务完成时被调用(被线程池的其他线程调用),不会阻塞主线程。
4、常见的异步任务场景
(1)、邮件发送
- 发送邮件是一个耗时操作,通常需要几秒钟甚至更长时间。使用异步任务线程可以在后台发送邮件,而不会阻塞主线程。
(2)、文件上传和下载
- 文件上传和下载操作通常涉及大量的I/O操作,使用异步任务线程可以避免阻塞主线程,提高系统的响应性。
(3)、数据处理和计算
- 对于复杂的数据处理和计算任务,使用异步任务线程可以将这些任务移到后台执行,释放主线程资源。
(4)日志记录
- 日志记录操作通常需要写入磁盘,使用异步任务线程可以避免阻塞主线程,提高系统的性能。
5、异步任务线程与异步请求处理的区别
前者是优化请求响应速度,把不重要或耗时的事情放在后台慢慢执行,主线程可以继续干其他事情或直接返回的一种处理方式;后者是并行可同时接受客户端的多个请求,两者完全不是一回事,需要注意下。
(1)、异步任务线程
- 用于处理耗时较长的后台任务。
- 通常由开发人员手动创建和管理。
- 使用@Async注解和TaskExecutor来实现。
即:用于处理耗时较长的后台任务,提高系统的响应性和并发处理能力。
(2)、异步请求处理
- 用于处理HTTP请求的异步响应。
- 通常由Web框架(如Spring MVC,springboot)自动支持。
- 使用CompletableFuture、DeferredResult等异步API来实现。
即:用于处理HTTP请求的异步响应,通常由Web框架自动支持。
6、如何使用异步任务
(1)、@EnableAsync
@EnableAsync注解只需要在一个配置类上启用一次,即可在整个应用程序中启用异步任务的支持。即:开启后会告诉Spring框架扫描并管理带有@Async注解的方法。
代码示例:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;@Configuration
@EnableAsync
public class AsyncConfig {// 配置类可以包含其他Bean和配置
}
(2)、@Async
1、@Async注解用于标记那些需要异步执行的方法上。注意,方法必须在一个Spring管理的Bean中,否则不会扫描到。
2、@Async标记的方法将在异步任务线程中执行,不会阻塞当前线程,而是立即返回一个Future对象或CompletableFuture对象。(这个Future对象现在是无法获取结果的,只能通过定义回调的方式用于异步任务完成后再去通知调用的线程,当然如果无需等待结果的也可以直接忽略返回结果)。
(3)、异步线程池
默认情况下,Spring是使用一个简单的线程池来执行异步任务。你也可以自定义线程池注入spring容器中,以更好地控制异步任务的执行。
3.1、自定义线程池示例
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration
@EnableAsync // 开启异步任务
public class AsyncConfig {@Bean // 注入线程池public ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(2);executor.setMaxPoolSize(5);executor.setQueueCapacity(100);executor.setThreadNamePrefix("Async-");executor.initialize();return executor;}
}
3.2、控制器示例
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AsyncController {@Autowiredprivate AsyncService asyncService;@GetMapping("/send-email")public String sendEmail(@RequestParam String recipient, @RequestParam String message) {// 调用异步方法CompletableFuture<String> result = asyncService.sendEmail(recipient, message);// 处理异步结果result.thenAccept(response -> { // 定义的回调方法,不会阻塞主线程,主线程会定义完成之后直接跳过该方法,往后执行。在异步任务完成后,真正执行回调方法代码的是线程池中的线程。System.out.println("Response: " + response); // 异步任务完成后,由线程池中的线程执行,主线程不会执行。});return "Request accepted, email will be sent asynchronously";}
}
3.3、异步方法
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;@Service
public class AsyncService {@Asyncpublic CompletableFuture<String> sendEmail(String recipient, String message) {// 模拟耗时操作try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}// 发送邮件System.out.println("Email sent to " + recipient + ": " + message);return CompletableFuture.completedFuture("Email sent successfully");}
}
解释一下:
1、异步方法的调用:
- 在
AsyncController的sendEmail方法中,调用asyncService.sendEmail方法。 sendEmail方法被标记为@Async,因此它会在一个异步任务线程中执行。- 方法调用会立即返回一个
CompletableFuture<String>对象,标识异步任务的结果对象。(这个对象现在是无法获取执行结果的,因为还没有执行完成,需要想要调用线程得到响应,可以通过定义回调的方式在异步任务完成后再通知调用的线程)。
2、处理异步结果: - 使用
result.thenAccept(response -> { ... })方法来处理异步任务的结果。 thenAccept方法注册一个回调函数,当异步任务完成时,回调函数会被调用,并传入任务的结果。- 这个回调函数在异步任务线程中执行,不会阻塞主线程。
3、立即返回响应: AsyncController的sendEmail方法在调用异步方法后立即返回一个字符串"Request accepted, email will be sent asynchronously"。- 这个响应告诉客户端请求已经被接受,邮件将在后台异步发送。
学海无涯苦作舟!!!
相关文章:
多线程篇-5--线程分类(线程类型,springboot中常见线程类型,异步任务线程)
常见的线程类型包括用户线程(User Threads)、守护线程(Daemon Threads)、主线程(Main Thread)、工作线程(Worker Threads)和线程池中的线程。 一、用户线程(User Thread…...
docker快速部署gitlab
文章目录 场景部署步骤默认账号密码效果 场景 新增了一台机器, 在初始化本地开发环境,docker快速部署gitlab 部署步骤 编写dockerfile version: 3.7services:gitlab:image: gitlab/gitlab-ce:latestcontainer_name: gitlabrestart: alwayshostname: gitlabenviron…...
C# 数据类型详解:掌握数据类型及操作为高效编码奠定基础
本文将带你深入了解C#中各种数据类型的特点、用途和最佳实践,让你不仅能熟练运用基本类型,还能掌握如何在实际项目中做出最合适的选择。 目录 C#基本语法 C#数据类型 C#类型转换 C#变量常量 C#基本语法 在学习C#之前我们要先知道C#的基础构建是由哪些…...
burp2
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
[ACTF2020 新生赛]BackupFile--详细解析
信息搜集 让我们寻找源文件,目录扫描: 找到了/index.php.bak文件,也就是index.php的备份文件。 后缀名是.bak的文件是备份文件,是文件格式的扩展名。 我们访问这个路径,就会直接下载该备份文件。 我们把.bak后缀删掉…...
循环神经网络(RNN)简述
RNN及其变体 1、概述 (一)、概念 RNN(Recurrent Neural Network), 中文称作循环神经网络, 它一般以序列数据为输入, 通过网络内部的结构设计有效捕捉序列之间的关系特征, 一般也是以序列形式进行输出。 RNN的循环机制使模型隐层**上一时间步产生的结果, 能够作为当下时间步…...
九、Ubuntu Linux操作系统
一、Ubuntu简介 Ubuntu Linux是由南非人马克沙特尔沃思(Mark Shutteworth)创办的基于Debian Linux的操作系统,于2004年10月公布Ubuntu是一个以桌面应用为主的Linux发行版操作系统Ubuntu拥有庞大的社区力量,用户可以方便地从社区获得帮助其官方网站:http…...
SpringBoot 新冠密接者跟踪系统:校园疫情防控的智能守护者
摘 要 信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古…...
【Ubuntu】E: Unable to locate package xxx
报错描述 在 Ubuntu 上 执行 apt install xxx 出现下面的报错: 即无法定位到该 Package,一般形式如下: # apt install xxx Reading package lists... Done Building dependency tree... Done Reading state information... Done E: Unable …...
vue多页面应用集成时权限处理问题
在多页面应用(MPA)中,权限管理通常会涉及到每个页面的访问控制、身份验证、以及权限校验。以下是几种常见的权限处理方式: 1. 前端路由权限控制 原理:虽然是多页面应用,通常每个页面会独立加载和渲染&…...
Socket编程(TCP/UDP详解)
前言:之前因为做项目和找实习没得空,计算机网络模块并没有写成博客,最近得闲了,把计算机网络模块博客补上。 目录 一,UDP编程 1)创建套接字 2)绑定端口号 3)发送与接收数据 4&…...
qt QConicalGradient详解
1、概述 QConicalGradient是Qt框架中QGradient的一个子类,它用于创建锥形渐变效果。锥形渐变是从一个中心点出发,沿着360度的圆周扩散的颜色渐变。这种渐变通常用于模拟光线旋转、创建彩虹效果或实现其他复杂的颜色过渡。QConicalGradient允许你定义渐变…...
存储过程与自然语言处理逻辑的不同与结合
在现代软件开发中,存储过程与自然语言处理(NLP)逻辑都发挥着重要作用。存储过程是一种在数据库内部运行的预编译程序,通常用于处理与数据相关的任务,例如插入、更新、删除数据以及复杂的查询操作。而自然语言处理&…...
了解Linux —— 理解其中的权限
前言 在了解Linux权限之前,先来探讨我们使用的shell 命令它到底是什么? Linux 是一个操作系统,我们称其为内核(kernel) ,正常情况下,我们一般用户操作并不是去直接使用内核,而是通过kernel 的外壳程序&…...
知识图谱嵌入与因果推理的结合
知识图谱通过节点(实体)和边(关系)来表示现实世界中的信息,但如何将这些信息转化为可进行推理和决策的形式,仍然是一个挑战。 另一方面,因果推理(Causal Inference)作为…...
STM32 PWM波形详细图解
目录 前言 一 PWM介绍 1.1 PWM简介 1.2 STM32F103 PWM介绍 1.3 时钟周期与占空比 二.引脚映像关系 2.1引脚映像与寄存器 2.2 复用功能映像 三. PWM 配置步骤 3.1相关原理图 3.2配置流程 3.2.1 步骤一二: 3.2.2 步骤三: 3.2.3 步骤四五六七: …...
Python Web 开发 FastAPI 入门:从基础架构到框架比较
Python Web 开发 FastAPI 入门:从基础架构到框架比较 目录 🖥️ Web 服务器概述(如 Nginx、Apache)🔗 前后端分离架构详解🔄 HTTP 路由和请求处理机制🧰 Web 框架概述:Django、Fla…...
基于STM32的智能仓库管理系统设计
目录 引言环境准备 硬件准备软件准备智能仓库管理系统基础 控制系统架构功能描述代码实现:实现智能仓库管理系统 4.1 RFID标签读取模块4.2 库存管理模块4.3 数据显示与监控模块4.4 无线通信模块应用场景:智能仓库管理系统优化问题解决方案与优化收尾与总…...
排序算法--堆排序【图文详解】
“留在码头的船才最安全” “但亲爱的,那不是造船的目的。 堆--插入heapInsert 原来有一个大根堆,如图: 现在要新插入一个数字50,进行插入 流程:和父亲相比,如果比父亲大,和父亲交换ÿ…...
FCBP 认证考试要点摘要
理论知识 数据处理与分析:包括数据的收集、清洗、转换、存储等基础操作,以及数据分析方法,如描述性统计分析、相关性分析、数据挖掘算法等的理解和应用 。数据可视化:涉及图表类型的选择与应用,如柱状图、折线图、饼图…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
