spring boot 開啟異步調用
1、啟動類上添加@EnableAsync注解,表示啟動異步
2、在具體實現異步的方法上添加@Async注解
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication
@EnableAsync
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}
package com.example.demo;import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** @Description: TODO* @author: sl* @date: 2024年05月30日 21:55*/
@Component
public class DemoController {/*** Async相當于是方法級別的線程,本身沒有自定義線程池更加靈活* 相當于是每進來一個請求就開啟一個線程,超過核心線程數小于最大線程數放入隊列,* 隊列滿了,繼續創建線程直至達到最大線程數* @throws InterruptedException*/@Asyncpublic void testSync() throws InterruptedException {Thread.sleep(2000);System.out.println("異步執行成功");}
}
測試執行?
package com.example.demo;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class DemoApplicationTests {@Autowiredprivate DemoController demoController;@Testvoid contextLoads() throws InterruptedException {demoController.testSync();System.out.println("主線程執行");Thread.sleep(4000);}}
執行結果?
執行原理
SpringBoot會默創建了一個線程池,使用這里面的線程來執行異步調用,在項目中使用
手動創建線程池異步調用?
常用線程池創建以及弊端
Executors 是一個 Java 中的工具類。提供四種線程池創建方式,工廠方法來創建不同類型的線程池。Executors 的創建線程池的方法,創建出來的線程池都實現了ExecutorService 接口,
1.newFiexedThreadPool(int Threads):創建固定數目線程的線程池。
2.newCachedThreadPool():創建一個可緩存的線程池,調用 execute將重用以前構造的線程(如果線程可用)。如果沒有可用的線程,則創建一個新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。
3.newSingleThreadExecutor() 創建一個單線程化的 Executor。
4.newScheduledThreadPool(int corePoolSize) 創建一個支持定時及周期性的任務執行的線程池,多數情況下可用來替代 Timer 類不建議大家使用Executors這個類來創建線程池呢,阿里開發手冊這樣定義:
【強制】線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式Executors 返回的線程池對象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool:
允許的請求隊列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM
2) CachedThreadPool 和 ScheduledThreadPool:
允許的創建線程數量為 Integer.MAX_VALUE, 可能會創建大量的線程,從而導致 OOM
使用常見的三種線程池創建方式,單一、可變、定長都有一定問題,原因是 FixedThreadPool 和 SingleThreadExecutor 底層都是用LinkedBlockingQueue 實現的,這個隊列最大長度為 Integer.MAX_VALUE,容易導致 OOM
所以實際生產一般自己通過 ThreadPoolExecutor 的 7 個參數,自定義線程池
spring boot創建線程池?
springboot創建線程池,Spring提供的對ThreadPoolExecutor封裝的線程池ThreadPoolTaskExecutor,直接使用注解啟用。
Async相當于是方法級別的線程,本身沒有自定義線程池更加靈活
package com.example.demo.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;/*** @Description: TODO* @author: sl* @date: 2024年05月30日 22:37*/
@Configuration
public class MyPoolConfig {@Beanpublic TaskExecutor taskExecutor(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//設置核心線程數executor.setCorePoolSize(10);//設置最大線程數executor.setMaxPoolSize(15);//設置隊列容量executor.setQueueCapacity(20);//設置線程活躍時間(秒)executor.setKeepAliveSeconds(60);//設置默認線程名稱executor.setThreadNamePrefix("1111-");//設置拒絕策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//等待所有任務結束后再關閉線程池executor.setWaitForTasksToCompleteOnShutdown(true);return executor;}}
在Async中指定線程池
package com.example.demo;import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;/*** @Description: TODO* @author: sl* @date: 2024年05月30日 21:55*/
@Component
public class DemoController {/*** Async相當于是方法級別的線程,本身沒有自定義線程池更加靈活* 相當于是每進來一個請求就開啟一個線程,超過核心線程數小于最大線程數放入隊列,* 隊列滿了,繼續創建線程直至達到最大線程數* @throws InterruptedException*/@Async("taskExecutor")public void testSync() throws InterruptedException {System.out.println(Thread.currentThread().getName());Thread.sleep(2000);System.out.println("異步執行成功");}
}