多线程业务异步处理

场景说明:

为什么需要异步方法?

合理使用异步方法可以让业务接口快到飞起!

异步方法适用于逻辑与逻辑之间可以相互分割互不影响的业务中, 如生成验证码和发送验证码组成的业务, 其实无需等到真正发送成功验证码才对客户端进行响应, 可以让短信发送这一耗时操作转为异步执行, 解耦耗时操作和核心业务;

同理还有文章阅读的业务逻辑 = 查询文章详情 + 更新文章阅读量后再响应客户端, 其实也无需等到阅读量更新后才响应文章详情给客户端, 用户查看文章是主要逻辑, 而文章阅读量更新是次要逻辑, 况且阅读量就算更新失败一点数据偏差也不会影响用户阅读因此这两个数据库操作之间的一致性是较弱的, 这类都能用异步事件去优化.

所以说: 恰当的在我们的Service中加入异步方法能大大提高接口的响应速度, 提升用户体验!

同步执行(同在一个线程中):

图片

异步执行(开启额外线程来执行):

图片

SpringBoot中的异步方法支持

其实, 在SpringBoot中并不需要我们自己去创建维护线程或者线程池来异步的执行方法, SpringBoot已经提供了异步方法支持注解.

@EnableAsync // 使用异步方法时需要提前开启(在启动类上或配置类上)
@Async // 被async注解修饰的方法由SpringBoot默认线程池(SimpleAsyncTaskExecutor)执行

1.多线程工具类

package com.test.business.common.thread;

import com.ruoyi.business.common.thread.exception.CustomAsyncExceptionHandler;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/***
 *   多线程-线程池
 *   @author wangwei
 *   @date 2023-08-25
 */

@EnableAsync // 开启多线程, 项目启动时自动创建
@Configuration
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(8);
        // 设置最大线程数
        executor.setMaxPoolSize(20);
        // 设置队列大小
        executor.setQueueCapacity(Integer.MAX_VALUE);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置线程名前缀+分组名称
        executor.setThreadNamePrefix("AsyncOperationThread-");
        executor.setThreadGroupName("AsyncOperationGroup");
        // 所有任务结束后关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 初始化
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }
}

2.业务具体使用

/**
     *
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertTbWjlz(TbWjlz tbWjlz) throws ParseException, ExecutionException, InterruptedException {
        DatedifferUtil datedifferUtil = new DatedifferUtil();
        Map<String, String> datediffer = datedifferUtil.datediffer(tbWjlz.getDtXfrqDate(), tbWjlz.getDtJzrqDate());
        String day = datediffer.get("day");
        if(Integer.parseInt(day)<=0){
            throw new CustomException("结束时间不能大于开始时间,请重新选择时间!");
        }
        tbWjlz.setCtId(UUID.randomUUID().toString(true));
        tbWjlz.setCtFunNo(FunNoConstants.NBGZ_WJLZ);

        int i = tbWjlzMapper.insertTbWjlz(tbWjlz);
        if (i != 1) {
            throw new CustomException("" + MessageConstants.DATA_DBADD_ERR);
        }
        CompletableFuture<Integer> future = insertTbTask(tbWjlz.getCtId(), tbWjlz.getCtCbmjId());

        //多线程异步任务处理
        // 循环等待异步请求结果
        int count = 0;
        while (true) {
            if (future.isCancelled()) {
                System.out.println("异步任务取消");
                break;
            }
            if (future.isDone()) {
                count = future.get();
                System.out.println("-------------------------------------------------异步发送任务数量: "+count+" 条");
                break;
            }
        }
        System.out.println("-------------------------------------------------异步发送任务成功,共发送: "+ +count+" 条");
        return i;
    }

3.发送待办

  private CompletableFuture<Integer> insertTbTask(String ctBussId, String ctCbmjId) {
        try {


            SysUser user = SecurityUtils.getLoginUser().getUser();
            TbTask task = new TbTask();
            task.setCtId(UUID.randomUUID().toString(true));
            task.setCtFunNo(FunNoConstants.NBGZ_WJLZ);
            task.setCtName("【文件流转任务】 " + user.getUserId() + " 指派给" + ctCbmjId + " 请签收完成!");
            int taskCode = taskMapper.insertTbTask(task);
            if (taskCode != 1) {
                throw new CustomException("任务发送" + MessageConstants.DATA_DBADD_ERR);
            }
        } catch (Exception e) {
            throw new CustomException(任务发送" + MessageConstants.DATA_DBADD_ERR);
        }
        return CompletableFuture.completedFuture(1);

    }

4.控制台打印的消息

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王大锤4391

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值