Spring面试大全@Async使用02

本文介绍了如何在SpringBoot项目中配置线程池,特别是使用@Async注解时的注意事项,包括线程池配置、线程名前缀的重要性以及为何不建议使用默认线程池。还讨论了@Async失效的情况,如未启用@EnableAsync和方法返回值非void/Future的问题。
摘要由CSDN通过智能技术生成

1. @Async的使用

  1. 在SpringBoot项目中创建application.yml配置文件
# 配置线程池
threadPoolTaskExecutor:
  corePoolSize: 10 # 核心线程数(默认线程数)
  maxPoolSize: 100 # 最大线程数
  keepAliveTime: 10 # 允许线程空闲时间(单位:默认为秒)
  queueCapacity: 200 # 缓冲队列数
  threadNamePrefix: executor-async- # 线程名统一前缀
server:
  port: 8099
spring:
  application:
    name: asyncServer

配置线程前缀名称原因?
方便溯源,因为并发环境下,出现的内存溢出等问题,非常不好排查,线程有名称方便我们排查问题

  1. 线程池配置
package com.lby.async.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @description 线程池配置
 */
@Configuration
public class ThreadPoolTaskExecutorConfig {

    /**
     * 核心线程数(默认线程数)
     */
    @Value("${threadPoolTaskExecutor.corePoolSize}")
    private int corePoolSize;

    /**
     * 最大线程数
     */
    @Value("${threadPoolTaskExecutor.maxPoolSize}")
    private int maxPoolSize;

    /**
     * 允许线程空闲时间(单位:默认为秒)
     */
    @Value("${threadPoolTaskExecutor.keepAliveTime}")
    private int keepAliveTime;

    /**
     * 缓冲队列数
     */
    @Value("${threadPoolTaskExecutor.queueCapacity}")
    private int queueCapacity;

    /**
     * 线程池名前缀
     */
    @Value("${threadPoolTaskExecutor.threadNamePrefix}")
    private String threadNamePrefix;


    @Bean("testTaskExecutor")
    public ThreadPoolTaskExecutor taskExecutor1() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);

        //线程池所使用的缓冲队列
        executor.setQueueCapacity(queueCapacity);
        //等待任务在关机时完成--表明等待所有线程执行完
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止
        executor.setKeepAliveSeconds(keepAliveTime);
        // 线程名称前缀
        executor.setThreadNamePrefix(threadNamePrefix);
        // 线程池对拒绝任务的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }

}
  1. 接口和实现类
public interface TestAsyncService {
    void testExecute();
    void testAsync1();
    void testAsync2();
}
@Service
@Slf4j
class TestAsyncServiceImpl implements TestAsyncService {
    @Resource(name = "testTaskExecutor")
    private ThreadPoolTaskExecutor testTaskExecutor;

    @Override
    public void testExecute() {
        testTaskExecutor.execute(() -> {
            log.info("testTaskExecutor.execute当前线程:" + Thread.currentThread().getName());
        });
    }
	// 指定了自定义线程池
    @Async("testTaskExecutor")
    @Override
    public void testAsync1() {
        log.info("testAsync1当前线程:" + Thread.currentThread().getName());
    }
	// 没有指定
    @Async
    @Override
    public void testAsync2() {
        log.info("testAsync2当前线程:" + Thread.currentThread().getName());
    }
}
  1. 单元测试
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class AsyncApplicationTests {
    @Autowired
    private TestAsyncService testAsyncService;
    @Test
    public void testExecute(){
        testAsyncService.testExecute();
    }
    @Test
    public void testAsync1(){
        testAsyncService.testAsync1();
    }
    @Test
    public void testAsync2(){
        testAsyncService.testAsync2();
    }
}
  1. 启动类
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class, args);
    }
}

2. @Async的使用为什么不建议使用默认的线程池

@Async默认线程池是SimpleAsyncTaskExecutor,里面默认配置线程最大数是Integer.Integer.MAX_VALUE,不对线程做限制,相当于每次使用都创建新线程,当并发量很高时严重影响性能,因此使用自定义的线程池

3. @Async失效的情况

  1. 启动类没有加@EnableAsync注解
  2. 方法不是pulibc
    因为@Async是通过代理执行的,代理无法拦截非public方法
  3. @Async方法不是被代理对象执行的,而是被当前类调用执行的
    因为@Async是通过代理对象调用执行的;如果我们通过普通(同步方法),调用异步@Async方法的就是当前对象,而不是当前类的代理对象
    例如:错误案例
@Component
public class MyService {
    @Async("自定义线程池")
    public void asyncMethod() {}
    // 下面就是就相当于普通方法的普通调用,无法使用异步
    public void normalMethod() {
        asyncMethod();
    }
}
  1. 方法的返回值不是void或者Future
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SuperLBY

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

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

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

打赏作者

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

抵扣说明:

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

余额充值