异步注解@Async使用自定义线程池

发布时间 2023-06-25 20:39:45作者: _mcj

1.@Async注解

@Async是java中一个注解,其作用就是加上该注解的类或方法能够异步执行任务,该注解添加到方法上时,表示该方法是异步方法,添加到类上时,表示该类中的所有方法都是异步方法。
该注解的代码为:image
可以看出其是作用在类和方法上,能够在运行时被获取到。
当在使用@Async时,如果不指定具体的线程池名称,那么其使用的是默认线程池SimpleAsyncTaskExecutor。而该线程池的默认配置为(在TaskExecutionProperties中):

  • 核心线程数:8
  • 容量:Integer.MAX_VALUE
  • 最大线程数:Integer.MAX_VALUE
  • 空闲线程存活时间:60s
  • 允许核心线程超时:true

由上面的配置可知在并发量很大的情况下,其会没有限制的创建线程,当线程数量到达一定程度之后,就会影响相应的性能了。因此,在使用@Async注解时,最好使用自定义线程池,也就是在注解中添加自定义线程池的名字。

2.示例代码

2.1 开启异步

添加@EnableAsync注解开启异步

@SpringBootApplication
@EnableAsync
public class Test2Application {

    public static void main(String[] args) {
        SpringApplication.run(Test2Application.class, args);
    }

}

2.2 配置自定义线程池

配置其线程池的实例名称为myselfExecutor,线程为myThread-开头的系列

@Configuration
@Slf4j
public class ThreadPoolConfig {

    private static final AtomicInteger poolNumber = new AtomicInteger(1);

    @Bean("myselfExecutor")
    public Executor myselfExecutor() {
        ThreadFactory threadFactory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(null, r, "myThread-" + poolNumber.getAndIncrement(), 0);
            }
        };
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10,
                20,
                30,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100),
                threadFactory);
        return executor;
    }

}

2.3 编写相应的方法与实现类

这边写了两个方法,一个testOne(),一个testTwo(),其中testOne()方法指明使用的线程池,而testTwo()方法则是使用默认的线程池。

public interface TestService {

    void testOne();

    void testTwo() throws InterruptedException;

}



@Service
@Slf4j
public class TestServiceImpl implements TestService{
    @Override
    @Async("myselfExecutor")
    public void testOne() {
        log.info("one test,当前线程为:" + Thread.currentThread().getName());
    }

    @Override
    @Async
    public void testTwo() throws InterruptedException {
        log.info("two test,当前线程为:" + Thread.currentThread().getName());
        Thread.sleep(1000);
    }
}

2.4 编写controller

写相关TestController的测试代码

@RestController
public class TestController {

    @Autowired
    TestService testService;

    @GetMapping("/get")
    public void get() throws InterruptedException {
        testService.testOne();
        testService.testTwo();
        testService.testOne();
    }


}

2.5 运行结果

image
可以从结果看出,执行testOne()方法的线程为myThread系列的线程,而执行testTwo()方法的线程为SimpleAsyncTaskExecutor。

3.@Async无效的情况

  • 没有加@EnableAsync注解
  • @Async修饰的方法不是public方法
  • @Async修饰的方法被static修饰了
  • 调用方法和@Async方法在同一个类中
  • @Async修饰的方法的返回值不是void或Future。ps:这个情况是会报错