springboot 线程池

news2024/11/14 16:23:56

为什么要使用线程池

使用线程池之后,不需要频繁的去创建和销毁线程(比如项目中手动创建线程,new Thread 类,我们可以把创建和销毁的线程的过程去掉),从而让线程得到重复的使用。并且可以对线程进行统一的管理。

在一个网页或应用程序中,每次请求都需要创建新的线程去处理,所以频繁的创建处理这些请求的线程非常消耗资源,为每个请求创建新线程将花费更多的时间,在创建和销毁线程时花费更多的系统资源。因此同时创建太多线程的JVM可能会导致系统内存不足,这就需要限制要创建的线程数,也就是需要使用到线程池。

springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行。

线程池的使用场景

  • 请求量大,任务执行时间短的业务。
  • 无论请求量大小,任务执行时间长的业务。

线程池工作原理

在这里插入图片描述
【图片转自网络】

创建线程池时,需要为他指定一个核心线程数,以及最大线程数,然后还需要给他配置一个任务队列

当我们把任务添加到线程池时,首先线程池会去判断是否有剩余的核心线程,如果有,他就会调用核心线程去执行本次任务。如果没有,他会去判断任务队列是否已满,如果没满,那他就会把本次任务添加到任务队列,否则他会去判断线程池中的最大线程数是否已满,如果已满,那么他会去执行他的一个拒绝策略,否则他会去调用非核心线程去执行本次任务

  • 主线程提交任务到线程池
  • 线程池判断当前线程池的线程数和核心线程数的大小,如果线程数小于核心线程数就新建线程处理任务;否则继续判断当前工作列队是否已满。
  • 如果当前工作队列未满,就将任务放到工作队列中,否则继续判断当前线程池的线程数和最大线程数的大小。
  • 如果当前线程池的线程数小于最大线程数,就新建线程处理请求,否则就执行拒绝策略。

线程池中的拒绝策略

  • AbortPolicy - 抛出RejectedExecutionException异常,终止任务。
  • CallerRunsPolicy - 使用调用线程执行任务。(交由主线程执行。如果执行程序已关闭,则会丢弃该任务
  • DiscardPolicy - 直接丢弃。(抛弃当前任务;会导致被抛弃的任务无法再次被执行
  • DiscardOldestPolicy - 丢弃队列最老任务,然后将本次任务添加到线程池。(抛弃工作队列中旧的任务,将新任务添加进队列;会导致被丢弃的任务无法再次被执行

简单使用

在springboot中为我们提供了线程池类,叫ThreadPoolTaskExecutor

  • 核心线程数:线程池创建时候初始化的线程数
  • 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
  • 缓冲队列:用来缓冲执行任务的队列

线程依赖于cpu,所以核心线程数量一般设置成cpu个数的两倍,最大线程数一般设置为cpu个数的四倍。

/config/ThreadPoolConfig.java

@Configuration	
public class ThreadPoolConfig {

	// 获取服务器的cpu个数
	private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();// 获取cpu个数
	private static final int COUR_SIZE = CPU_COUNT * 2;
	private static final int MAX_COUR_SIZE = CPU_COUNT * 4;

	// 接下来配置一个bean,配置线程池。
	@Bean
	public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
		ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
		threadPoolTaskExecutor.setCorePoolSize(COUR_SIZE);// 设置核心线程数
		threadPoolTaskExecutor.setMaxPoolSize(MAX_COUR_SIZE);// 配置最大线程数
		threadPoolTaskExecutor.setQueueCapacity(MAX_COUR_SIZE * 4);// 配置队列容量(这里设置成最大线程数的四倍)
		threadPoolTaskExecutor.setThreadNamePrefix("test-thread");// 给线程池设置名称
		threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 设置任务的拒绝策略
		return threadPoolTaskExecutor;
	}
}

/controller/ThreadPoolController.java

@RestController
public class ThreadPoolController {

	private final Logger logger = LoggerFactory.getLogger(ThreadPoolController.class);

	@Resource
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;

	@GetMapping("/thread")
	public Result testThread() {
		threadPoolTaskExecutor.execute(() -> {
			Thread.sleep(10000);// 为了演示方便,让变成休眠10秒
			logger.info("执行线程池任务");
			logger.info(Thread.currentThread().getName());//打印线程名称
		});// 需要传递Runnable对象

		logger.info("主线程名称:{}", Thread.currentThread().getName());//再打印主线程名称
		return Result.success("success");
	}
}

启动服务后,访问localhost:8080/thread。然后看控制台,能看出先打印了主线程名称,然后过了10秒,打印了"执行线程池任务"和子线程名称。

主线程名称:http-nio-8002-exec-1
执行线程池任务 // 10秒后...
test-thread1 // 10秒后...

将Service层的服务异步化

/config/ThreadPoolConfig.java

@Configuration	
@EnableAsync//开启异步调用
public class ThreadPoolConfig {
	...
}

创建controller,开发一个http服务接口,里面会调用service层的服务。将Service层的服务异步化,这样每次调用都会都被提交到线程池异步执行。

/service/TestService.java

public interface TestService {
    void test();
}

/service/TestServiceImpl.java

@Service
public class TestServiceImpl implements TestService {
	private static final Logger logger = LoggerFactory.getLogger(TestServiceImpl.class);
	
	@Override
	@Async("threadPoolTaskExecutor")// 提交到线程池中去处理
	public void test() {
		logger.info("start service");
		try{
			Thread.sleep(1000);
		}catch(Exception e){
			e.printStackTrace();
		}
		logger.info("end service");
	}
}

/controller/ThreadPoolController.java

@RestController
public class ThreadPoolController {

	private static final Logger logger = LoggerFactory.getLogger(ThreadPoolController.class);

	@Autowired
    	private TestService testService;

	@GetMapping("/thread")
	public String testThread() {
		logger.info("start controller");
		testService.test();
		logger.info("end controller");
	}
}

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

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

相关文章

手把手教你用 Python 搭建一个图像分类器

深度学习是使用人工神经网络进行机器学习的一个子集,目前已经被证明在图像分类方面非常强大。 尽管这些算法的内部工作在数学上是严格的,但 Python 库(比如 keras)使这些问题对我们所有人都可以接近。 在本文中,我将介绍一个简单的图像分类…

机器人中的数值优化之最速下降法

本文ppt来自深蓝学院《机器人中的数值优化》 目录 1 迭代方向 2 步长的选择 3 Armijo condition 4 非精确线搜索的优势 1 迭代方向 梯度方向是函数上升最快的方向,而负梯度方向则是函数下降最快的方向,因此最速下降法就是以负梯度方向为迭代方向…

二叉树的构造和相关功能的代码实现及解析

目录 一.二叉树类的定义 二.构造二叉树(构造函数) 三.为二叉树插入节点(insert_value) 四.移除根节点(remove_root,lchild_leaf) 五.移除二叉树中的某值(remove,remove_value) 六.清空二叉树 七.前、中、后序遍历 一.二叉树类的定义 二叉树类的定…

Django入门学习-了解基本模块

目录 MVT设计了解 认识MVT 实际操作 Template: View: 路由配置 Model: 默认的后台管理模块 初始化admin模块 应用中Admin注册 MVT设计了解 认识MVT Django的web设计模型是MVT: Model:数据存储层,处理所有数据相关的业…

idea+ApifoxUploader+Apifox真是内外双修,香

前言 最近部门为整合后端组、前端组、测试组、需求组、产品组等组之间的工作流程,旨在提高协调与高效,其中之一就是希望开发组(后端、前端)开发的接口能及时更新,测试组能做接口测试,后期方便出文档&#x…

大公司为什么禁止SpringBoot项目使用Tomcat?

本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~ Github地址:https://github.com/…

【2】burpsuite屏蔽浏览器无用流量包方法

0x01 问题描述经常会使用火狐或者谷歌去burpsuite对站点进行测试,但是在测试的过程中burpsuite经常抓到火狐浏览器自身的数据包或者其他无用的数据包,这就对我们工作的效率大有影响,所以这里来告诉大家如何解决此类问题。0x02 问题复现访问网…

星环科技数据治理与数据价值评估实践分享

数据价值评估背景 自2015年8月国务院《促进大数据发展行动纲要》提出“数据已成为国家基础性战略资源”以来,我国出台了诸多政策和法案,推进数据的发展和数据要素的资产化。 2019年10月,第十九届四中全会关于《推进国家治理体系和治理能力现…

Node.js安装详细教程

安装 Node.js 官网下载安装包https://nodejs.org/zh-cn/,一直【下一步】安装即可。 设置Windows操作系统全局环境变量 为什么设置环境变量? 当我们在cmd命令行中输入命令时,系统首先会在当前目录下去找命令对应的可执行程序,如果…

后端校验(hibernate-validator)

目录一、介绍和依赖二、方法的 Model 参数校验三、方法的非 Model 参数校验四、常用注解五、快速失败六、自定义校验规则一、介绍和依赖 hibernate-validator 是 Java 中常用的后端校验框架 https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/【…

提取各种数据结构中的元素将提取结果合并为迭代对象 itertools.chain(*a,b)

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 提取各种数据结构中的元素 将提取结果合并为迭代对象 itertools.chain(*a,b) [太阳]选择题 以下python代码最后输出正确的一项是? from itertools import chain a[(1, A), (2, B), …

Java高效率复习-线程基础[线程]

内容大纲 线程相关概念 并发并行 当只有一个CPU时,会执行并发的效果,在多个应用程序之间快速切换,而有多个CPU时,则多个CPU独立执行,而当进程多于CPU个数时,则会出现并发并行的情况,总有一个CPU…

如何炼就数据分析的思维?

目录 前言结构化思维假说演绎思维指标化思维维度分析思维 前言 面对数据异常,我们经常会出现“好像是A原因引起的?”“貌似和B原因也相关?““有可能是 C操作不当“的主观臆测。 或者,拿到一个分析议题,分析”11 月销售…

@ConfigurationProperties注解使用方法(内含源代码)

ConfigurationProperties注解使用方法(内含源代码) 源代码下载链接地址:https://download.csdn.net/download/weixin_46411355/87400774 目录ConfigurationProperties注解使用方法(内含源代码)源代码下载链接地址&…

怎么识别截图中的文字?这三个方法让你轻松学会

在日常工作或学习中,我们会经常在网上查阅一些资料,当遇到一些优美的句子或者段落时,都会手动摘抄下来,这种记录方式不仅很耗时,还耗费精力,并且现在很多网站都已经不支持文本复制了,遇到这种情…

6.验证面试高频问题整理(附答案)

目录 Q126.top-down phase、bottom-up phase有哪些 Q127.为什么build_phase是top-down phase,connect_phase是bottom-up phase Q128.$size用于packed array和unpacked array分别得到的什么 Q129.class和struct的异同 Q130.class和module的异同 Q131.对象创建的…

MAC系统 LightGBM模型转为pmml格式

一、配置JAVA环境和Maven环境 参考以下两个博客即可 MAC 系统安装 JDK 及环境变量配置_蜗牛的博客-CSDN博客_mac jdk环境变量配置 MAC 系统安装 Maven 及环境变量配置_蜗牛的博客-CSDN博客_mac安装mpv 二、下载JPMML-LightGBM 先在Git上下载 直接下载或使用git clone http…

Aop切面编程原理和Spring实现

Aop切面编程概念 AOP切面编程一般可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现 日志处理,权限控制,性能检测,事务控制等 AOP实现的原理就是动态代理,在有接口的情况下,使用JDK动态代理,在没有接口的情况下使用cglib动态代理 为Dao层所有的add方法…

字体反爬,一种来自字体设计师的跨行反爬案例 | 案例 28

本篇博客涉及的内容非常有价值,尤其是在反爬领域。 核心内容为自定义字体文件反爬。 文章目录准备工作在 Web 页面中使用字体文件整理文字编码Flask 中随机一串数字,渲染到前台总结准备工作 在正式编写代码前,需要先安装 FontCreator &#…

GeoServer学习笔记-01GeoSever运行编译

一、运行1. 下载GeoServerGitHub仓库地址:https://github.com/geoserver/geoserver2.本地代码工具打开项目在idea里,文件->新建->来自现有的源代码项目,选择项目的pom文件加载项目。3.idea编译环境设置(1)设置jd…