天天看点

八、SpringBoot整合多线程异步前言一、异步调用实现二、@Async整合线程池

目录

  • 前言
  • 一、异步调用实现
  • 二、@Async整合线程池

前言

  • @Async实际就是多线程封装的
  • 异步线程执行方法有可能会非常消耗cpu的资源,所以大的项目建议使用Mq异步实现

一、异步调用实现

  • 1.启动类需要添加注解

    @EnableAsync

@SpringBootApplication
@EnableAsync
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}
           
  • 2.需要执行异步的方法上加上注解

    @Async

    • 注意失效问题:如果异步注解写当前自己类,有可能aop会失效,无法拦截注解,最终导致异步注解失效,需要经过代理类调用接口;所以需要将异步的代码单独抽取成一个类调用接口
@RestController
@Slf4j
public class MemberService {

    @Autowired
    private MemberServiceAsync memberServiceAsync;

    @RequestMapping("/addMember")
    public String addMember() {
        // 1.数据库插入数据
        log.info(">01<");

        memberServiceAsync.sms();
        log.info(">04<");
        return "用户注册成功";
    }
}
           
@Component
@Slf4j
public class MemberServiceAsync {
    @Async
    public String sms() {
        log.info(">02<");
        try {
            log.info(">正在发送短信..<");
            Thread.sleep(3000);
        } catch (Exception e) {

        }
        log.info(">03<");
        return "短信发送完成!";
    }
}
           
八、SpringBoot整合多线程异步前言一、异步调用实现二、@Async整合线程池

二、@Async整合线程池

  • 1.在第一点的例子中虽然我们实现了异步多线程,但是还有缺点
    • 每次都重新开启一个线程,这样非常消耗资源影响效率
    • 我们需要整合线程池来优化,提高程序的性能
      八、SpringBoot整合多线程异步前言一、异步调用实现二、@Async整合线程池
  • 2.项目结构
八、SpringBoot整合多线程异步前言一、异步调用实现二、@Async整合线程池
  • 3.ThreadPoolConfig
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
public class ThreadPoolConfig {

    /**
     * 每秒需要多少个线程处理?
     * tasks/(1/taskcost)
     */
    private int corePoolSize = 3;

    /**
     * 线程池维护线程的最大数量
     * (max(tasks)- queueCapacity)/(1/taskcost)
     */
    private int maxPoolSize = 3;

    /**
     * 缓存队列
     * (coreSizePool/taskcost)*responsetime
     */
    private int queueCapacity = 10;

    /**
     * 允许的空闲时间
     * 默认为60
     */
    private int keepAlive = 100;

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(corePoolSize);
        // 设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        // 设置队列容量
        executor.setQueueCapacity(queueCapacity);
        // 设置允许的空闲时间(秒)
        //executor.setKeepAliveSeconds(keepAlive);
        // 设置默认线程名称
        executor.setThreadNamePrefix("thread-");
        // 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}
           
  • 4.在@Async()注解中配置属性"taskExecutor"
@Component
@Slf4j
public class MemberServiceAsync {
    @Async("taskExecutor")
    public String sms() {
        log.info(">02<");
        try {
            log.info(">正在发送短信..<");
            Thread.sleep(3000);
        } catch (Exception e) {

        }
        log.info(">03<");
        return "短信发送完成!";
    }
    /**
     * 线程池
     */
}