Spring (TaskExecutor)
implements multithreading and concurrent programming through task executors . Use ThreadPoolTaskExecutor
can be realized based on a thread pool TaskExecutor
. In actual development, tasks are generally non-blocking, that is, asynchronous, so we have to @EnableAsync
enable support for asynchronous tasks in the configuration class , and @Async
declare that it is an asynchronous task by using annotations in the method of the actual executed Bean .
One, Maven
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Two, configuration class
package com.example.config;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreadPoolTaskExecutor
*/
@Configuration
@ComponentScan("com.example") // 定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中
@EnableAsync // 利用@EnableAsync注解开启异步任务支持
public class CustomMultiThreadingConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5); // 核心线程数
taskExecutor.setMaxPoolSize(10); // 最大线程数
taskExecutor.setQueueCapacity(25); ///配置队列大小
taskExecutor.setThreadNamePrefix("async-service-"); // 配置线程池前缀
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 配置拒绝策略
taskExecutor.initialize(); // 数据初始化
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
}
}
Capture thread exception information
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Slf4j
@Component
public class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.info("------------->>>捕获线程异常信息");
log.info("Exception message - " + throwable.getMessage());
log.info("Method name - " + method.getName());
for (Object param : objects) {
log.info("Parameter value - " + param);
}
}
}
ThredPoolTaskExcutor processing flow
When the pool size is less than corePoolSize
, on the new thread, and processes the request
when the pool size is equal corePoolSize
, put into the request workQueue
, the idle thread pool workQueue go fetch processing task and
when workQueue
the time does not fit the task into the pool on the new thread, and the processing request, if the pool size to hold maximumPoolSize
, to use RejectedExecutionHandler
to do the processing refuse
when the pond is greater than the number of threads corePoolSize
, the thread waits for the extra keepAliveTime
time, if no request may be processed to self-destruct
Three, create thread task
package com.example.service.impl;
import com.example.service.TestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class TestServiceImpl implements TestService {
private Logger logger = LoggerFactory.getLogger(TestServiceImpl.class);
/**
* 通过@Async注解表明该方法是一个异步方法,
* 如果注解在类级别上,则表明该类所有的方法都是异步方法,而这里的方法自动被注入使用ThreadPoolTaskExecutor作为TaskExecutor
*/
@Async
public void executeAsyncTask1(Integer i) {
logger.info("CustomMultiThreadingService ==> executeAysncTask1 method: 执行异步任务{} ", i);
}
@Async
public void executeAsyncTask2(Integer i) {
logger.info("CustomMultiThreadingService ==> executeAsyncTask2 method: 执行异步任务{} ", i);
}
}
Four, test
package com.example.controller;
import com.example.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping(value = "/testController")
public class TestController {
@Autowired
private TestService testService;
@ResponseBody
@RequestMapping(value = "/doTask")
public String doTask() {
for (int i = 0; i < 10; i++) {
testService.executeAsyncTask1(i);
testService.executeAsyncTask2(i);
}
return "success";
}
}