異步調用就是不用等待結果的返回就執行後面的邏輯,同步調用則須要等帶結果再執行後面的邏輯。java
一般咱們使用異步操做都會去建立一個線程執行一段邏輯,而後把這個線程丟到線程池中去執行,代碼以下:面試
ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(() -> { try { // 業務邏輯 } catch (Exception e) { e.printStackTrace(); } finally { } });
這樣的方式看起來沒那麼優雅,儘管用了java的lambda。在Spring Boot中有一種更簡單的方式來執行異步操做,只須要一個@Async註解便可。spring
@Async public void saveLog() { System.err.println(Thread.currentThread().getName()); }
咱們能夠直接在Controller中調用這個業務方法,它就是異步執行的,會在默認的線程池中去執行。須要注意的是必定要在外部的類中去調用這個方法,若是在本類調用是不起做用的,好比this.saveLog()。 最後在啓動類上開啓異步任務的執行,添加@EnableAsync便可。緩存
另外關於執行異步任務的線程池咱們也能夠自定義,首先咱們定義一個線程池的配置類,用來配置一些參數,具體代碼以下:微信
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; /** * 異步任務線程池配置 * * @author yinjihuan */ @Configuration @ConfigurationProperties(prefix = "spring.task.pool") public class TaskThreadPoolConfig { //核心線程數 private int corePoolSize = 5; //最大線程數 private int maxPoolSize = 50; //線程池維護線程所容許的空閒時間 private int keepAliveSeconds = 60; //隊列長度 private int queueCapacity = 10000; //線程名稱前綴 private String threadNamePrefix = "FSH-AsyncTask-"; public String getThreadNamePrefix() { return threadNamePrefix; } public void setThreadNamePrefix(String threadNamePrefix) { this.threadNamePrefix = threadNamePrefix; } public int getCorePoolSize() { return corePoolSize; } public void setCorePoolSize(int corePoolSize) { this.corePoolSize = corePoolSize; } public int getMaxPoolSize() { return maxPoolSize; } public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; } public int getKeepAliveSeconds() { return keepAliveSeconds; } public void setKeepAliveSeconds(int keepAliveSeconds) { this.keepAliveSeconds = keepAliveSeconds; } public int getQueueCapacity() { return queueCapacity; } public void setQueueCapacity(int queueCapacity) { this.queueCapacity = queueCapacity; } }
而後咱們從新定義線程池的配置:異步
import java.lang.reflect.Method; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration public class AsyncTaskExecutePool implements AsyncConfigurer { private Logger logger = LoggerFactory.getLogger(AsyncTaskExecutePool.class); @Autowired private TaskThreadPoolConfig config; @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(config.getCorePoolSize()); executor.setMaxPoolSize(config.getMaxPoolSize()); executor.setQueueCapacity(config.getQueueCapacity()); executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); executor.setThreadNamePrefix(config.getThreadNamePrefix()); //線程池對拒絕任務(無線程可用)的處理策略,目前只支持AbortPolicy、CallerRunsPolicy //AbortPolicy:直接拋出java.util.concurrent.RejectedExecutionException異常 --> //CallerRunsPolicy:主線程直接執行該任務,執行完以後嘗試添加下一個任務到線程池中,能夠有效下降向線程池內添加任務的速度 --> //DiscardOldestPolicy:拋棄舊的任務、暫不支持;會致使被丟棄的任務沒法再次被執行 --> //DiscardPolicy:拋棄當前任務、暫不支持;會致使被丟棄的任務沒法再次被執行 --> executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {// 異步任務中異常處理 return new AsyncUncaughtExceptionHandler() { @Override public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) { logger.error("=========================="+arg0.getMessage()+"=======================", arg0); logger.error("exception method:" + arg1.getName()); } }; } }
配置完以後咱們的異步任務執行的線程池就是咱們自定義的了,咱們能夠經過在屬性文件裏面配置線程池的大小等等信息,也可使用默認的配置:ide
spring.task.pool.maxPoolSize=100
最後講下線程池配置的拒絕策略,當咱們的線程數量高於線程池的處理速度時,任務會被緩存到本地的隊列中,隊列也是有大小的,若是超過了這個大小,咱們須要有拒絕的策略,否則就會內存溢出了,目前支持2種拒絕策略:this
推薦相關閱讀:線程
《反射面試題-請了解下》code
更多技術分享請加我微信,我拉你進羣進行交流: