SpringBoot中使用多线程的方法示例
作者:BouncingFish 发布时间:2021-05-24 19:56:04
一、介绍
Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用Spring提供的ThreadPoolTaskExecutor来创建一个基于线城池的TaskExecutor。在使用线程池的大多数情况下都是异步非阻塞的。节省更多的时间,提高效率。
工作原理
当主线程中调用execute接口提交执行任务时:则执行以下步骤:注意:线程池初始时,是空的。
如果当前线程数<corePoolSize,如果是则创建新的线程执行该任务
如果当前线程数>=corePoolSize,则将任务存入BlockingQueue
如果阻塞队列已满,且当前线程数<maximumPoolSize,则新建线程执行该任务。
如果阻塞队列已满,且当前线程数>=maximumPoolSize,则抛出异常RejectedExecutionException,告诉调用者无法再接受任务了。
在Springboot中对其进行了简化处理,只需要配置一个类型为java.util.concurrent.TaskExecutor或其子类的bean,并在配置类或直接在程序入口类上声明注解@EnableAsync,即可可以开启异步任务。
调用也简单,在由Spring管理的对象的方法上标注注解@Async,声明是异步任务,显式调用即可生效。
二、声明
让配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreasPoolTaskExecutor,就可以获取一个基于线程池的TaskExecutor
使用注解@EnableAsync开启异步,会自动扫描
@Configuration
@EnableAsync
public class ThreadConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(15);
executor.setQueueCapacity(25);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
三、调用
通过@Async注解表明该方法是异步方法,如果注解在类上,那表明这个类里面的所有方法都是异步的
@Service
public class AsyncTaskService {
@Async
public void executeAsyncTask(int i) {
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
}
}
四、进阶
有时候我们不止希望异步执行任务,还希望任务执行完成后会有一个返回值,在java中提供了Future泛型接口,用来接收任务执行结果,springboot也提供了此类支持,使用实现了ListenableFuture接口的类如AsyncResult来作为返回值的载体。比如上例中,我们希望返回一个类型为String类型的值,可以将返回值改造为:
@Async
public Future<String> executeAsyncTaskWithResult2(int i) {
System.out.println("线程" + Thread.currentThread().getName() + " 开始执行异步任务" + i);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + " 结束执行异步任务" + i);
return new AsyncResult<>("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
}
调用返回值:
get()是阻塞式,等待当前线程完成才返回值
public void threadTest() {
try {
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 20; i++) {
futures.add(asyncTaskService.executeAsyncTaskWithResult2(i));
}
// 获取值。get是阻塞式,等待当前线程完成才返回值
for (Future<String> future : futures) {
System.out.println("返回结果:" + future.get());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
补充
实际上,@Async还有一个参数,通过Bean名称来指定调用的线程池-比如上例中设置的线程池参数不满足业务需求,可以另外定义合适的线程池,调用时指明使用这个线程池-缺省时springboot会优先使用名称为'taskExecutor'的线程池,如果没有找到,才会使用其他类型为TaskExecutor或其子类的线程池。
来源:https://juejin.cn/post/6940133431485399047


猜你喜欢
- 本文实例为大家分享了java模拟实现电话本系统的具体代码,供大家参考,具体内容如下java 模拟 电话本系统 (基础版)需求:注意的是,联系
- 一、新建短信微服务1、在service模块下创建子模块service-msm2.创建controller和service代码3.配置appl
- SQLite是Android自带的关系型数据库,是一个基于文件的轻量级数据库。Android提供了3种操作数据的方式,SharedPrefe
- 写在前面并发编程一直都存在,只不过过去的很长时间里,比较难以实现,随着互联网的发展,人口红利的释放,更加友好的支持并发编程已经成了主流编程语
- 与任何程序设计语言一样,Java使用条件语句和循环结构确定控制流。本文将简单讲解条件、循环和switch。一、块作用域块(block),即复
- using Word;下面的例子中包括C#对Word文档的创建、插入表格、设置样式等操作:(例子中代码有些涉及数据信息部分被省略,重要是介绍
- 本文实例讲述了Android返回键功能的实现方法。分享给大家供大家参考。具体如下:在开发android应用时,常常通过按返回键(即keyCo
- 映射匹配兼容性前面我们已经能从表中查询出数据,并将数据封装到模型类中,这整个过程涉及到一张表和一个模型类:之所以数据能够成功的从表中获取并封
- 整理文档,java 动态增加定时任务示例,直接上代码。import org.apache.tools.ant.util.DateUtils;
- 本文实例为大家分享了Android手机开发设计之记事本功能,供大家参考,具体内容如下一、需求分析1.1业务需求分析近年来,随着生活节奏的加快
- 一.搭建1.前端npm installnpm run serve2.后端老生常谈的配置,修改mysql与redis即可。二.业务功能介绍功能
- 用途项目中使用了 dubbo,注册中心使用的 zookeeper,使用 zookeeper 实现了一个简单的分布式锁(依赖 curator)
- 本文实例为大家分享了javaweb登录验证码的具体代码,供大家参考,具体内容如下使用:Controller:生成验证码@RequestMap
- 网站优化必做的事情之一,百度ping,主动推送给百度文章添加时调用百度推送方法//保存protected void btnSubmit_Cl
- 安卓提供的列表选择框(Spinner)相当于web端用户注册时的选择下拉框,比如注册候选择省份城市等。如下图便是一个列表选择框下拉列表的列表
- 本文介绍 Spring Boot 项目中整合 ElasticSearch 并实现 CRUD 操作,包括分页、滚动等功能。之前在公司使用 ES
- 目前市面上的第三方短信服务平台数量十分庞大,并能为企业提供三网合一的短信接口,这些服务商通过整合短信发送服务,简单的打包成为API和SDK接
- 先新建一个文件夹kun,kun就是类所在的package。新建一个java文件。HelloWorld.java的代码如下:package k
- 在上篇文章跟大家介绍了Android之使用Android-query框架开发实战(一),本文继续跟大家介绍有关Android-query框架
- 将来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参数化。用于“行为请求者”与“行为实现者”解耦,可实现二者之间的松耦合,以便