Spring boot通过@EnableAsync
、@Async
配合来实现异步调用的。
举一个理发店的例子吧,比如3位理发师,5位顾客来理发。
下面上代码
通过@EnableAsync
、@Configuration
配置一个默认的线程池,充当理发师CorePoolSize(3);
即3位理发师
import org.springframework.aop.interceptor.AsyncExecutionAspectSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@EnableAsync
@Configuration
public class ThreadPoolConfig {
@Bean(name = AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME)
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(10);
executor.setKeepAliveSeconds(60);
executor.setThreadGroupName("理发师-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
理发业务,haircut方法上面添加 @Async(value = "taskExecutor")
表示方法异步,异步的方法不能被当前类的方法互相调用,在同一个类内部调用一个异步方法,不会触发异步
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CountDownLatch;
@Service
@Slf4j
public class DemoServiceImpl {
@Async(value = "taskExecutor")
public void haircut(CountDownLatch countDownLatch, String user) {
log.info("用户:{},开始理发", user);
try {
//模拟耗时
Thread.sleep(5000L);
} catch (InterruptedException e) {
}
log.info("用户:{},理发完成", user);
countDownLatch.countDown();
}
}
写一个单侧,营业开始,5为顾客来理发,都理发完成,营业结束
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.CountDownLatch;
@SpringBootTest
@Slf4j
public class DemoServiceImplTest {
@Autowired
private DemoServiceImpl demoService;
@Test
public void haircutBusiness() {
log.info("理发店:开始营业");
CountDownLatch countDownLatch = new CountDownLatch(5);
demoService.haircut(countDownLatch, "张三");
demoService.haircut(countDownLatch, "李四");
demoService.haircut(countDownLatch, "王五");
demoService.haircut(countDownLatch, "马六");
demoService.haircut(countDownLatch, "孙七");
try {
countDownLatch.await();
} catch (InterruptedException e) {
}
log.info("理发店:关闭营业");
}
}
运行结果如下:时间点和效果符合预期
CountDownLatch 定义了5个顾客同时来理发,实际并发还是按照线程池配置3个理发师来处理的
2022-10-19 18:04:10.356 [main] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImplTest[19] - 理发店:开始营业
2022-10-19 18:04:10.363 [taskExecutor-1] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[15] - 用户:张三,开始理发
2022-10-19 18:04:10.363 [taskExecutor-2] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[15] - 用户:李四,开始理发
2022-10-19 18:04:10.363 [taskExecutor-3] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[15] - 用户:王五,开始理发
2022-10-19 18:04:15.379 [taskExecutor-3] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[20] - 用户:王五,理发完成
2022-10-19 18:04:15.379 [taskExecutor-3] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[15] - 用户:马六,开始理发
2022-10-19 18:04:15.379 [taskExecutor-1] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[20] - 用户:张三,理发完成
2022-10-19 18:04:15.380 [taskExecutor-2] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[20] - 用户:李四,理发完成
2022-10-19 18:04:15.380 [taskExecutor-1] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[15] - 用户:孙七,开始理发
2022-10-19 18:04:20.380 [taskExecutor-3] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[20] - 用户:马六,理发完成
2022-10-19 18:04:20.380 [taskExecutor-1] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImpl[20] - 用户:孙七,理发完成
2022-10-19 18:04:20.381 [main] INFO org.sauceggplant.manage.demo.service.impl.DemoServiceImplTest[29] - 理发店:关闭营业
感兴趣童鞋可以自己试一下,good luck!