簡(jiǎn)介
大部分的情況我們的代碼的執(zhí)行都是按照代碼的調(diào)用順序來(lái)從頭執(zhí)行到尾。打印出線程的名字是http-nio-8080-exec-x 某個(gè)線程。在我們執(zhí)行異步任務(wù)的時(shí)候需要?jiǎng)?chuàng)建線程池來(lái)處理異步任務(wù)。
修改啟動(dòng)main
@SpringBootApplication
@EnableAsync
@EnableScheduling
public class StudySpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(StudySpringbootApplication.class, args);
}
}
創(chuàng)建線程池
線程池雖好但也要做好隔離。如果所有的業(yè)務(wù)都應(yīng)用一個(gè)線程池,當(dāng)其中的一個(gè)業(yè)務(wù)把線程池占滿,就會(huì)影響其他的業(yè)務(wù)正常的運(yùn)作。我們可以設(shè)置幾個(gè)線程池來(lái)定制化為需要的業(yè)務(wù)。列如: pool1 為異步任務(wù), pool2 為定時(shí)任務(wù)防止定時(shí)任務(wù)沖突導(dǎo)致任務(wù)的丟棄。
@Configuration
public class PoolConfig {
@Bean(name = "pool1")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 設(shè)置核心線程數(shù)
executor.setCorePoolSize(5);
// 設(shè)置最大線程數(shù)
executor.setMaxPoolSize(10);
// 設(shè)置隊(duì)列容量
executor.setQueueCapacity(20);
// 設(shè)置線程活躍時(shí)間(秒)
executor.setKeepAliveSeconds(60);
// 設(shè)置默認(rèn)線程名稱
executor.setThreadNamePrefix("wh1-");
// 設(shè)置拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任務(wù)結(jié)束后再關(guān)閉線程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
@Bean(name = "pool2")
public ThreadPoolTaskExecutor taskExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 設(shè)置核心線程數(shù)
executor.setCorePoolSize(2);
// 設(shè)置最大線程數(shù)
executor.setMaxPoolSize(4);
// 設(shè)置隊(duì)列容量
executor.setQueueCapacity(20);
// 設(shè)置線程活躍時(shí)間(秒)
executor.setKeepAliveSeconds(60);
// 設(shè)置默認(rèn)線程名稱
executor.setThreadNamePrefix("wh2-");
// 設(shè)置拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任務(wù)結(jié)束后再關(guān)閉線程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
建異步服務(wù)
@Service
public class TaskAsyncService {
/**
* 無(wú)返回值
* @throws Exception
*/
@Async(value = "pool1")
public void taskOne() throws Exception {
Thread.sleep(4000);
System.out.println("task one " + Thread.currentThread().getName());
}
/**
* 無(wú)返回值
* @throws Exception
*/
@Async(value = "pool1")
public void taskTwo() throws Exception {
System.out.println("task two " + Thread.currentThread().getName());
}
/**
* 有返回值回調(diào)的異步任務(wù)
* @return
* @throws Exception
*/
@Async(value = "pool1")
public Future<String> taskOne2() throws Exception {
Thread.sleep(4000);
System.out.println("task one " + Thread.currentThread().getName());
return new AsyncResult<>("task one done");
}
/**
* 有返回值回調(diào)的異步任務(wù)
* @return
* @throws Exception
*/
@Async(value = "pool1")
public Future<String> taskTwo2() throws Exception {
System.out.println("task two " + Thread.currentThread().getName());
return new AsyncResult<>("task two done");
}
}
創(chuàng)建action
@GetMapping("/async-test")
public Response taskTest() throws Exception {
/**
* 1.執(zhí)行http 請(qǐng)求任務(wù)的線程是 http-nio-8080-exec ,
* 2.執(zhí)行 異步任務(wù)的線程是自定義線程池中的某個(gè)線程
* 3.如果定時(shí)任務(wù)中的線程默認(rèn)是開(kāi)啟一個(gè)線程,可以通過(guò) @Async 指定線程池中的某個(gè)線程
*/
System.out.println("taskTest thread name : " + Thread.currentThread().getName());
//無(wú)返回值
//asyncService.taskOne();
//asyncService.taskTwo();
Future<String> future1 = asyncService.taskOne2();
Future<String> future2 = asyncService.taskTwo2();
while (true){
if(future1.isDone() && future2.isDone()){
System.out.println("異步調(diào)用完成 : " + future1.get() + future2.get());
break;
}
}
//調(diào)用同步函數(shù)
this.test1();
return new Response(0, "success");
}
public void test1(){
System.out.println("function test1 : " + Thread.currentThread().getName());
}
定時(shí)任務(wù)
@Service
public class ScheduleTask {
@Async(value = "pool2")
@Scheduled(fixedRate = 5000)
public void task1(){
/**猜測(cè)是維持一個(gè)線程 來(lái)處理定時(shí)任務(wù),如果多個(gè)定時(shí)任務(wù)沖突,這個(gè)線程會(huì)丟棄掉這個(gè)任務(wù)*/
System.out.println("schedele task1 :" + Thread.currentThread().getName());
}
}
打印日志
## 方法執(zhí)行
taskTest thread name : http-nio-8080-exec-1
task two wh1-2
task one wh1-1
異步調(diào)用完成 : task one donetask two done
function test1 : http-nio-8080-exec-1
##定時(shí)任務(wù)
schedele task1 :wh2-2
schedele task1 :wh2-1