需要在启动类加入@EnableAsync使异步调用@Async注解生效
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@SpringBootApplication
@MapperScan({"com.example.demo.dao","com.example.demo.practice"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
springboot的线程池配置
创建一个配置类AsyncExecutorConfig,用来定义如何创建一个ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync这两个注解,表示这是个配置类,并且是线程池的配置类,如下所示:
package com.example.demo;
import lombok.extern.slf4j.Slf4j;
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.ThreadPoolExecutor;
/**
* 异步线程池
*/
@Slf4j
@Configuration
@EnableAsync
public class AsyncExecutorConfig {
/**
* 默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,
* 当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
* 当队列满了,就继续创建线程,当线程数量大于等于maxPoolSize后,开始使用拒绝策略拒绝
*/
/** 核心线程数(默认线程数) */
private static final int corePoolSize = 2;
/** 最大线程数 */
private static final int maxPoolSize = 2;
/** 允许线程空闲时间(单位:默认为秒) */
private static final int keepAliveTime = 2;
/** 缓冲队列大小 */
private static final int queueCapacity = 999;
/** 线程池名前缀 */
private static final String threadNamePrefix = "Async-practice-";
@Bean("asyncExecutor") // bean的名称,默认为首字母小写的方法名,如果不声明则会使用方法名
public ThreadPoolTaskExecutor asyncExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
// CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
使用
controller:
package com.example.demo.controller;
import com.example.demo.service.TestService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/mainController")
@AllArgsConstructor(onConstructor_ = {@Autowired})
@Api(tags = "测试异步调用",value = "类标识value")
public class AsyncController {
@GetMapping(value = "/testYB")
@ApiOperation(value = "测试异步注解 @Async" ,notes = "")
public String testYB(){
return testService.testYB();
}
@GetMapping(value = "/mainMethod")
@ApiOperation(value = "测试数据库连接" ,notes = "方法描述notes")
public int main(){
return testService.getServiceValues();
}
TestService testService;
}
service:
package com.example.demo.service;
import com.example.demo.dao.TestDao;
import com.example.demo.util.rest.HttpParams;
import com.example.demo.util.rest.Mail;
import com.example.demo.util.rest.Rest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@AllArgsConstructor(onConstructor_ = {@Autowired})
public class TestService {
public String testYB(){
log.info("主线程开始"+new Date().toString());
for(int i = 1; i <= 5; i++){
testYbLongTime.longTime();
}
log.info("主线程结束"+new Date().toString());
return "service返回";
}
public void testYBVoid(){
System.out.println("开始"+new Date().toString());
testYbLongTime.longTimeVoid();
System.out.println("结束"+new Date().toString());
}
/**
* @Method
* @Author yu
* @Version 1.0
* @Description 测试配置文件的注入
* @param
* @Return
* @Exception
* @Date 2020/5/9
*/
public int getServiceValues(){
System.out.println(mail.getPort()+"--"+mail.getUrl());
List<HttpParams> aa = rest.getParamsList();
Map<String,String> bb = new HashMap<>();
bb.put("1","2") ;
bb.put("3","3") ;
bb.put("4","4") ;
// lamda2foreach.add(bb);
System.out.println(lamda2foreach.iMap(bb));
return testDao.testMethod();
}
TestDao testDao;
Mail mail;
Rest rest;
Lamda2foreach lamda2foreach;
TestYbLongTime testYbLongTime;
}
异步方法:
package com.example.demo.service;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.util.Date;
@Slf4j
@Component
public class TestYbLongTime {
@Async("asyncExecutor")
public void longTimeVoid(){
try {
Thread.sleep(1000*5);
log.info("线程完成");
log.info("123");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Async("asyncExecutor")
public void longTime(){
try {
Thread.sleep(1000*5);
log.info("异步线程完成"+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
注意事项:
1>、:@Async()没有指定线程池时,默认是使用springboot默认线程池,且每次都会创建线程,所以最好我们来自定义一个线程池。
2>、调用异步的方法和异步方法不要再同一个类中,使用注入的方式调用
3>、异步方法不要使用private、static修饰
在spring中的配置:(没有用过可以参考:https://blog.csdn.net/Muscleheng/article/details/81409672)