# springboot-threadpool **Repository Path**: wzk9261/springboot-threadpool ## Basic Information - **Project Name**: springboot-threadpool - **Description**: 在 Spring Boot 中创建线程池 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-01-07 - **Last Updated**: 2024-01-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 线程池配置 ## 注释掉 @Configuration 如果把两个线程池类的`@Configuration`都注释掉,那么会使用默认线程池,默认线程池的命名为`task-n`,n 为整数。如果线程池中的任务消耗完,会使用主线程 main。 ```java 2020-01-10 16:53:12.931 INFO 4236 --- [ main] c.j.s.threadpool.task.AsyncTaskTest : All tasks finished. 2020-01-10 16:53:12.952 INFO 4236 --- [ task-1] c.j.s.threadpool.task.AsyncTask : Task0 started. ``` ## 注释掉 @Async 如果把`AsyncTask`类的`doTask`方法上的`@Aync`注释掉,那么执行`doTask`方法的都将会是主线程,即同步顺序执行。 ## 线程池的标准写法 [官网](https://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/scheduling/annotation/EnableAsync.html)提供的标准写法: ```java @Configuration @EnableAsync public class AppConfig implements AsyncConfigurer { @Bean public MyAsyncBean asyncBean() { return new MyAsyncBean(); } @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(7); executor.setMaxPoolSize(42); executor.setQueueCapacity(11); executor.setThreadNamePrefix("MyExecutor-"); executor.initialize(); return executor; } } ``` # 高并发 ## 模拟耗时操作 ### 异步邮件 假定发送注册邮件是一个耗时操作(耗时 3 s),那么我们可以使用线程去异步执行该操作。 ```java @Slf4j @Service public class EmailServiceImpl implements EmailService { @Override @Async public void sendEmail(String username) { log.info("开始向{}@mastermind.com发送邮件", username); ThreadUtils.sleep(3000); log.info("邮件发送成功!"); } } ``` ### 注册逻辑 ```java @Service public class RegisterServiceImpl implements RegisterService { @Autowired private EmailService emailService; @Override public boolean checkUsername(String username) throws Exception { if (username == null) { throw new Exception("用户名不能为null"); } boolean isExisted = username.equalsIgnoreCase("jake") || username.equalsIgnoreCase("heather"); if (!isExisted) { emailService.sendEmail(username); } return !isExisted; } } ``` ```java @RestController @RequestMapping("register") public class RegisterController { @Autowired private RegisterService registerService; @GetMapping("") public String register(String username) throws Exception { return registerService.checkUsername(username)?"注册成功":"用户名已被占用"; } } ``` 上述代码简单模拟了注册过程,当用户名不为 jake 或 heather 时,即表示该用户名没被占用,可以注册。如果`sendEmail`没有加上`@Aync`注解,那么会变为同步执行,用户在注册过程中不得不等待 3 s;但加上了`@Aync`注解后,会由线程池中的线程异步执行,能够马上返回注册成功的信息给客户端。 ## 单元测试模拟高并发 在`RegisterControllerTest`中,基于 MockMVC 模拟 100 个用户并发访问注册接口,这 100 个用户全都能够立即获取到注册成功的反馈。 ```java public class RegisterControllerTest extends BaseControllerTest { /** * 模拟100个用户同时访问注册接口 */ @Test public void register() throws Exception { for (int i = 1; i <= 100; i++) { assertEquals("注册成功", singleRegister(i)); } } private String singleRegister(int i) throws Exception { MultiValueMap params = new LinkedMultiValueMap<>(); params.add("username", "guest" + i); return mockGet("/register", params); } } ```