AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

淺析Spring中Async注解底層異步線程池原理

來源: 責編: 時間:2024-06-14 08:53:49 127觀看
導讀一、前言開發中我們經常會用到異步方法調用,具體到代碼層面,異步方法調用的實現方式有很多種,比如最原始的通過實現Runnable接口或者繼承Thread類創建異步線程,然后啟動異步線程;再如,可以直接用java.util.concurrent包提供

一、前言

開發中我們經常會用到異步方法調用,具體到代碼層面,異步方法調用的實現方式有很多種,比如最原始的通過實現Runnable接口或者繼承Thread類創建異步線程,然后啟動異步線程;再如,可以直接用java.util.concurrent包提供的線程池相關API實現異步方法調用。REv28資訊網——每日最新資訊28at.com

如果說可以用一行代碼快速實現異步方法調用,那是不是比上面方法香很多。REv28資訊網——每日最新資訊28at.com

Spring提供了Async注解,就可以幫助我們一行代碼搞定異步方法調用。Async注解用起來是很爽,但是如果不對其底層實現做深入研究,難免有時候也會心生疑慮,甚至會因使用不當,遇見一些讓人摸不著頭腦的問題。REv28資訊網——每日最新資訊28at.com

本文首先將對Async注解做簡單介紹,然后和大家分享一個我們項目中因Async注解使用不當的線上問題,接著再深扒Spring源碼,對Async注解底層異步線程池的實現原理一探究竟。REv28資訊網——每日最新資訊28at.com

二、Async注解簡介

REv28資訊網——每日最新資訊28at.com

Async注解定義源碼

REv28資訊網——每日最新資訊28at.com

圖片圖片REv28資訊網——每日最新資訊28at.com

從源碼可以看出@Async注解定義很簡單,只需要關注兩點:REv28資訊網——每日最新資訊28at.com

  • Target({ElementType.TYPE, ElementType.METHOD})標志Async注解可以作用在方法和類上,作用在類上時,類的所有方法可以實現異步調用。
  • String value( ) default ""是唯一字段屬性,用來指定異步線程池,且該字段有缺省值。

REv28資訊網——每日最新資訊28at.com

Async注解異步調用實現原理概述REv28資訊網——每日最新資訊28at.com

REv28資訊網——每日最新資訊28at.com

在Spring框架中,Async注解的實現是通過AOP來實現的。具體來說,Async注解是由AsyncAnnotationAdvisor這個切面類來實現的。REv28資訊網——每日最新資訊28at.com

AsyncAnnotationAdvisor類是Spring框架中用于處理Async注解的切面,它會在被Async注解標識的方法被調用時,創建一個異步代理對象來執行方法。這個異步代理對象會在一個新的線程中調用被@Async注解標識的方法,從而實現方法的異步執行。REv28資訊網——每日最新資訊28at.com

在AsyncAnnotationAdvisor中,會使用AsyncExecutionInterceptor來處理Async注解。AsyncExecutionInterceptor是實現了MethodInterceptor接口的類,用于攔截被Async注解標識的方法的調用,并在一個新的線程中執行這個方法。REv28資訊網——每日最新資訊28at.com

通過AOP的方式實現Async注解的異步執行,Spring框架可以在方法調用時動態地創建代理對象來實現異步執行,而不需要在業務代碼中顯式地創建新線程。REv28資訊網——每日最新資訊28at.com

總的來說,Async注解的實現是通過AOP機制來實現的,具體的切面類是AsyncAnnotationAdvisor,它利用AsyncExecutionInterceptor來處理被Async注解標識的方法的調用,實現方法的異步執行。REv28資訊網——每日最新資訊28at.com

三、Async注解底層異步線程池原理探究

REv28資訊網——每日最新資訊28at.com

獲取Async注解線程池主流程解析

REv28資訊網——每日最新資訊28at.com

進入到Spring源碼Async注解AOP切面實現部分,我們重點剖析異步調用實現中線程池是怎么處理的。下圖是org.springframework.aop.interceptor.AsyncExecutionInterceptor#invoke方法的實現,可以看出是調用determineAsyncExecutor方法獲取異步線程池。REv28資訊網——每日最新資訊28at.com

AsyncExecutionInterceptor#invokeAsyncExecutionInterceptor#invokeREv28資訊網——每日最新資訊28at.com

下圖是determineAsyncExecutor方法實現:REv28資訊網——每日最新資訊28at.com

圖片圖片REv28資訊網——每日最新資訊28at.com

圖片圖片REv28資訊網——每日最新資訊28at.com

左圖為AsyncExecutionInterceptor#determineAsyncExecutor,右圖為AsyncExecutionAspectSupport#getExecutorQualifierREv28資訊網——每日最新資訊28at.com

REv28資訊網——每日最新資訊28at.com

從代碼實現中可以看到determineAsyncExecutor獲取線程池的大致流程:REv28資訊網——每日最新資訊28at.com

determineAsyncExecutor獲取線程池流程determineAsyncExecutor獲取線程池流程REv28資訊網——每日最新資訊28at.com

如果在使用Async注解時指定了自定義線程池比較好理解,如果使用Async注解時沒有指定自定義線程池,Spring是怎么處理默認線程池呢?繼續深入源碼看看Spring提供的默認線程池的實現。REv28資訊網——每日最新資訊28at.com

REv28資訊網——每日最新資訊28at.com

Spring是怎么為Async注解提供默認線程池的

REv28資訊網——每日最新資訊28at.com

Async注解默認線程池有下面兩個方法實現:   REv28資訊網——每日最新資訊28at.com

  • org.springframework.aop.interceptor.AsyncExecutionInterceptor#getDefaultExecutor
  • org.springframework.aop.interceptor.AsyncExecutionAspectSupport#getDefaultExecutor

AsyncExecutionInterceptor#getDefaultExecutorAsyncExecutionInterceptor#getDefaultExecutorREv28資訊網——每日最新資訊28at.com

可以看出AsyncExecutionInterceptor#getDefaultExecutor方法比較簡單:先嘗試調用父類AsyncExecutionAspectSupport#getDefaultExecutor方法獲取線程池,如果父類方法獲取不到線程池再用創建SimpleAsyncTaskExecutor對象作為Async的線程池返回。REv28資訊網——每日最新資訊28at.com

AsyncExecutionAspectSupport#getDefaultExecutorAsyncExecutionAspectSupport#getDefaultExecutorREv28資訊網——每日最新資訊28at.com

再來看父類AsyncExecutionAspectSupport#getDefaultExecutor方法的實現,可以看到Spring根據類型從Spring容器中獲取TaskExecutor類的實例,先記住這個關鍵點。REv28資訊網——每日最新資訊28at.com

我們知道,Spring根據類型獲取實例時,如果spring容器中有且只有一個指定類型的實例對象,會直接返回,否則的話,會拋出NoUniqueBeanDefinitionException異常或者NoSuchBeanDefinitionException異常。REv28資訊網——每日最新資訊28at.com

但是,對于Executor類型,Spring容器卻“網開一面”,有一個特殊處理:當從Spring容器中獲取Executor實例對象時,如果滿足@ConditionalOnMissingBean(Executor.class)條件,Spring容器會自動裝載一個ThreadPoolTaskExecutor實例對象,而ThreadPoolTaskExecutor是TaskExecutor的實現類。REv28資訊網——每日最新資訊28at.com

圖片圖片REv28資訊網——每日最新資訊28at.com

圖片圖片REv28資訊網——每日最新資訊28at.com

左圖為TaskExecutionAutoConfiguration,右圖為TaskExecutionPropertiesREv28資訊網——每日最新資訊28at.com

從TaskExecutionProperties和TaskExecutionAutoConfiguration兩個配置類我們看到Spring自動裝載的ThreadPoolTaskExecutor線程池對象的參數:核心線程數=8;最大線程數=Integer.MAX_VALUE;隊列大小=Integer.MAX_VALUE。REv28資訊網——每日最新資訊28at.com

四、總結

現在Async注解線程池源碼已經看的差不多了,下面這張圖是Spring處理Async異步線程池的流程:REv28資訊網——每日最新資訊28at.com

REv28資訊網——每日最新資訊28at.com

REv28資訊網——每日最新資訊28at.com

Async異步線程池獲取流程Async異步線程池獲取流程REv28資訊網——每日最新資訊28at.com

歸納一下:如果在使用Async注解時沒有指定自定義的線程池會出現以下幾種情況:REv28資訊網——每日最新資訊28at.com

  • 當Spring容器中有且僅有一個TaskExecutor實例時,Spring會用這個線程池來處理Async注解的異步任務,這可能會踩坑,如果這個TaskExecutor實例是第三方jar引入的,可能會出現很詭異的問題。
  • Spring創建一個核心線程數=8、最大線程數=Integer.MAX_VALUE、隊列大小=Integer.MAX_VALUE的線程池來處理Async注解的異步任務,這時候也可能會踩坑,由于線程池參數設置不合理,核心線程數=8,隊列大小過大,如果有大批量并發任務,可能會出現OOM。
  • Spring創建SimpleAsyncTaskExecutor實例來處理Async注解的異步任務,SimpleAsyncTaskExecutor不是一個好的線程池實現類,SimpleAsyncTaskExecutor根據需要在當前線程或者新線程中執行異步任務。如果當前線程已經有空閑線程可用,任務將在當前線程中執行,否則將創建一個新線程來執行任務。由于這個線程池沒有線程管理的能力,每次提交任務都實時創建新城,所以如果任務量大,會導致性能下降。

本文鏈接:http://www.tebozhan.com/showinfo-26-93708-0.html淺析Spring中Async注解底層異步線程池原理

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: React 19 全覽,新特性進行一次深度的體驗學習

下一篇: 618 入手三星 Galaxy Tab S9 系列 解鎖購物「新」方式

標簽:
  • 熱門焦點
Top