当前位置: 首页 > news >正文

SpringBoot开启异步多线程

前言:

        SpringBoot 的异步多线程需要从 java 的多线程基础说起,可以参考 java 多线程实现的三种方式区别。SpringBoot 在此基础上进行了多次封装,所以使用起来非常方便。

一、核心参数说明

        ThreadPoolExecutor 是 java 的核心线程池类;Spring 对 ThreadPoolExecutor 进行二次封装形成了 ThreadPoolTaskExecutor,其中几个核心参数除了名字略有改动,核心含义没变,下面说明一下:

  • corePoolSize:核心线程池数
  • maxPoolSize:最大线程池数
  • queueCapacity:线程池队列最大容量
  • keepAliveSeconds:允许线程的空闲时间,核心线程外的线程在空闲时间到达后会被销毁
  • threadNamePrefix:线程池名的前缀
  • rejectedExecutionHandler:拒绝策略

其中拒绝策略是线程达到某种饱和后的线程池的操作策略,总共四种:

  • AbortPolicy:如果线程池队列满了丢掉任务并且抛出RejectedExecutionException异常
  • DiscardPolicy:如果线程池队列满了,会直接丢掉这个任务并且不会抛出异常
  • DiscardOldestPolicy:如果队列满了,会将最早进入队列的任务删掉,再尝试加入队列
  • CallerRunsPolicy:如果添加到线程池失败,那么主线程会自己去执行该任务

说明一下几个核心参数和拒绝策略是怎么工作的:

1.核心线程数:m,最大线程数: n(一般 n > m),线程池队列最大容量: i,线程总数: j;

2.线程进场后(s<m),线程会直接启动直到启动的线程数达到核心线程数(s=m);

3.线程继续进场(m<s<m+j),线程开始排队,此时启动的线程数不会增加直到队列饱和(s=m+j);

4.线程继续进场(m+j<s<n+j),每进场一个线程,相应排在队列前的线程会启动一个;直到启动的线程达到最大线程数(s=n+j);

5.线程继续进场(s>n+j),此时触发拒绝策略;

二、使用说明

  首先配置线程池:

@Configuration
@EnableAsync
public class ThreadPoolConfig {

    @Bean("normalThreadPool")  //线程池实例名,多个线程池配置需要声明,一个线程池可有可无
    public Executor executorNormal() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(3);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("NORMAL--");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        return executor;
    }
}

其次在需要异步的方法上加 @Async 注解:

@Slf4j
@Service
public class ThreadTaskService {

    @Async("normalThreadPool") //多个线程池配置时需指定配置实例
    public void task() {
        log.info("task start...");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("task end...");
    }

}

异步的调用跟普通 service 方法没区别:

@Slf4j
@RestController
@RequestMapping("/thread")
public class ThreadTaskController {

    @Autowired
    ThreadTaskService taskService;

    @GetMapping(value = "/start")
    public String getValue() {
        taskService.task();
        return "hello...";
    }
}

三、带返回值的异步

要获取异步函数的返回值可以使用 Future,但是Future 的get方法是阻塞的,使用时需要注意。

    @Async("normalThreadPool")
    public CompletableFuture<String> task() {
        String result = "000";
        log.info("task start...");
        try {
            Thread.sleep(5000);
            result = "333";
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("task end...");
        return CompletableFuture.completedFuture(result);
    }
@Slf4j
@RestController
@RequestMapping("/thread")
public class ThreadTaskController {
    @Autowired
    ThreadTaskService taskService;

    @GetMapping(value = "/start")
    public String getValue() throws ExecutionException, InterruptedException {

        CompletableFuture<String> result = taskService.task();

        log.info("result:{}", result.get()); // get 方法会使主线程阻塞

        return "hello...";
    }
}

四、几种异步失败的情况

1. 异步方法使用static关键词修饰;

2. 缺少 @EnableAsync 注解;

3. 同一个类中,一个方法调用另外一个有@Async注解的方法(原因是@Async注解的方法,是在代理类中执行的);

相关文章:

  • 计算机毕业设计ssm企业员工培训管理系统2q63c系统+程序+源码+lw+远程部署
  • C语言-手写Map(数组+链表+红黑树)(全功能)
  • 雅思写作课程 band 7+1
  • 人工智能畅想——《人工智能简史》读后感
  • Python 和 Selenium – 用于数据科学的爬虫教程
  • 在虚拟机上使用SoftRoCE部署SPDK NVMe-oF
  • ListMap集合
  • 分享一个查题公众号系统平台 好用且简单
  • WebWall-10.Over Permisson(越权漏洞)
  • 搜题系统平台 公众号查题必用
  • Linux(七)DNS域名解析服务器学习
  • c++基础(八)——静态成员
  • 【手把手带你学JavaSE系列】练习项目—图书管理系统
  • iptables实战
  • JavaScript心得笔记-1(后端了解必备)
  • [deviceone开发]-do_Webview的基本示例
  • IOS评论框不贴底(ios12新bug)
  • Javascript弹出层-初探
  • node入门
  • Rancher-k8s加速安装文档
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • vue的全局变量和全局拦截请求器
  • 高性能JavaScript阅读简记(三)
  • 实现简单的正则表达式引擎
  • 学习Vue.js的五个小例子
  • 移动端解决方案学习记录
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​插件化DPI在商用WIFI中的价值
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • ​一些不规范的GTID使用场景
  • # 飞书APP集成平台-数字化落地
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • (03)光刻——半导体电路的绘制
  • (1)Android开发优化---------UI优化
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (一)kafka实战——kafka源码编译启动
  • (正则)提取页面里的img标签
  • .bat文件调用java类的main方法
  • .NET CF命令行调试器MDbg入门(一)
  • .net core webapi 大文件上传到wwwroot文件夹
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • /etc/shadow字段详解
  • @EventListener注解使用说明
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)
  • [bzoj1901]: Zju2112 Dynamic Rankings
  • [Editor]Unity Editor类常用方法
  • [hihocoder1395] 最大权闭合子图
  • [HOW TO]怎么在iPhone程序中实现可多选可搜索按字母排序的联系人选择器
  • [IMX6DL] CPU频率调节模式以及降频方法
  • [Latex学习笔记]数学公式基本命令