spring 使用 thread(多线程)
在Java项目中,多线程的使用是非常普遍的;例如:当具体的业务实现后,一边需要返回给前端,一边又需要添加到日志表中,如果等添加到日志表中之后再返回前端,就浪费时间;这时就需要多线程来处理!
1。定义配置类(ThreadConfig)
package com.sun.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
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.lang.reflect.Method;
import java.util.concurrent.Executor;
/**
* @author SunHaidong
* @date 2021-03-08 9:26
*/
//声明为配置类
@Configuration
//启用异步任务
@EnableAsync
//日志,可以不需要
@Slf4j
public class ThreadConfig implements AsyncConfigurer{
//以下数据 根据业务需求自己配置合适的数量
private final int corePoolSize = 10;
private final int maxPoolSize = 15;
private final int queueCapacity = 25;
private final String threadNamePrefix = "MyThread-";
//1.getAsyncExecutor:自定义线程池,若不重写会使用默认的线程池。
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//corePoolSize:核心线程数;核心线程会一直存活,即使没有任务需要执行
executor.setCorePoolSize(corePoolSize);
//maxPoolSize:最大线程数;当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
executor.setMaxPoolSize(maxPoolSize);
//queueCapacity:任务队列容量(阻塞队列);当核心线程数达到最大时,新任务会放在队列中排队等待执行
executor.setQueueCapacity(queueCapacity);
//threadNamePrefix:线程名称前缀
executor.setThreadNamePrefix(threadNamePrefix);
//initialize:初始化
executor.initialize();
return executor;
}
//2.getAsyncUncaughtExceptionHandler:捕捉IllegalArgumentException异常.
//有些spring 版本中没有这个方法,可以不用写
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SpringAsyncExceptionHandler();
}
//自定义异常处理器,可以不写, 让上面的方法(AsyncUncaughtExceptionHandler)直接 return null;
class SpringAsyncExceptionHandler implements AsyncUncaughtExceptionHandler{
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.info("Exception message - " + throwable.getMessage());
log.info("Method name - " + method.getName());
for (Object param : objects) {
log.info("Parameter value - " + param);
}
}
}
}
2.编写service方法
package com.sun.thread;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* @author SunHaidong
* @date 2021-03-08 9:37
*/
@Service
public class ThreadService {
// 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行
@Async
public void test1(){
System.out.println("test1 : " + Thread.currentThread().getName());
//业务代码区 A
//演示需要,真实业务中可以不用写
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行
@Async
public void test2(){
System.out.println("test2 : " + Thread.currentThread().getName());
//业务代码区 B
//演示需要,真实业务中可以不用写
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.编写测试类
@Test
void testThread(){
for (int i = 0; i < 10; i++ ){
threadService.test1();
threadService.test2();
}
}
4.配置类(ThreadConfig)也可以使用xml 文件配置
<task:annotation-driven executor="annotationExecutor"/>
<!-- 支持 @Async 注解 -->
<task:executor id="annotationExecutor" pool-size="5-20" queue-capacity="10" keep-alive="5" rejection-policy="DISCARD"/>