需要在啓動類加入@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)