自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

2行代碼,讓接口性能提升10倍

新聞 前端
logservice中有個(gè)log方法用來記錄日志,當(dāng)調(diào)用logService.log(msg)的時(shí)候,希望異步執(zhí)行,那么可以通過@EnableAsync & @Async來實(shí)現(xiàn)。

[[334572]]

 1、本文內(nèi)容

詳解 @EnableAsync & @Async,主要分下面幾個(gè)點(diǎn)進(jìn)行介紹。

  1. 作用
  2. 用法
  3. 獲取異步執(zhí)行結(jié)果
  4. 自定義異步執(zhí)行的線程池
  5. 自定義異常處理
  6. 線程隔離
  7. 源碼 & 原理

2、作用

spring容器中實(shí)現(xiàn)bean方法的異步調(diào)用。

比如有個(gè)logService的bean,logservice中有個(gè)log方法用來記錄日志,當(dāng)調(diào)用logService.log(msg)的時(shí)候,希望異步執(zhí)行,那么可以通過@EnableAsync & @Async來實(shí)現(xiàn)。

3、用法

2步

  1. 需要異步執(zhí)行的方法上面使用@Async注解標(biāo)注,若bean中所有的方法都需要異步執(zhí)行,可以直接將@Async加載類上。
  2. 將@EnableAsync添加在spring配置類上,此時(shí)@Async注解才會(huì)起效。

常見2種用法

  1. 無返回值的
  2. 可以獲取返回值的

4、無返回值的

用法

方法返回值不是Future類型的,被執(zhí)行時(shí),會(huì)立即返回,并且無法獲取方法返回值,如:

  1. @Async 
  2. public void log(String msg) throws InterruptedException { 
  3.     System.out.println("開始記錄日志," + System.currentTimeMillis()); 
  4.     //模擬耗時(shí)2秒 
  5.     TimeUnit.SECONDS.sleep(2); 
  6.     System.out.println("日志記錄完畢," + System.currentTimeMillis()); 

案例

實(shí)現(xiàn)日志異步記錄的功能。

LogService.log方法用來異步記錄日志,需要使用@Async標(biāo)注

  1. package com.javacode2018.async.demo1; 
  2.  
  3. import org.springframework.scheduling.annotation.Async; 
  4. import org.springframework.stereotype.Component; 
  5.  
  6. import java.util.concurrent.TimeUnit; 
  7.  
  8. @Component 
  9. public class LogService { 
  10.     @Async 
  11.     public void log(String msg) throws InterruptedException { 
  12.         System.out.println(Thread.currentThread() + "開始記錄日志," + System.currentTimeMillis()); 
  13.         //模擬耗時(shí)2秒 
  14.         TimeUnit.SECONDS.sleep(2); 
  15.         System.out.println(Thread.currentThread() + "日志記錄完畢," + System.currentTimeMillis()); 
  16.     } 

來個(gè)spring配置類,需要加上@EnableAsync開啟bean方法的異步調(diào)用.

  1. package com.javacode2018.async.demo1; 
  2.  
  3. import org.springframework.context.annotation.ComponentScan; 
  4. import org.springframework.context.annotation.EnableAspectJAutoProxy; 
  5. import org.springframework.scheduling.annotation.EnableAsync; 
  6.  
  7. @ComponentScan 
  8. @EnableAsync 
  9. public class MainConfig1 { 

測試代碼

  1. package com.javacode2018.async; 
  2.  
  3. import com.javacode2018.async.demo1.LogService; 
  4. import com.javacode2018.async.demo1.MainConfig1; 
  5. import org.junit.Test; 
  6. import org.springframework.context.annotation.AnnotationConfigApplicationContext; 
  7.  
  8. import java.util.concurrent.TimeUnit; 
  9.  
  10. public class AsyncTest { 
  11.  
  12.     @Test 
  13.     public void test1() throws InterruptedException { 
  14.         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 
  15.         context.register(MainConfig1.class); 
  16.         context.refresh(); 
  17.         LogService logService = context.getBean(LogService.class); 
  18.         System.out.println(Thread.currentThread() + " logService.log start," + System.currentTimeMillis()); 
  19.         logService.log("異步執(zhí)行方法!"); 
  20.         System.out.println(Thread.currentThread() + " logService.log end," + System.currentTimeMillis()); 
  21.  
  22.         //休眠一下,防止@Test退出 
  23.         TimeUnit.SECONDS.sleep(3); 
  24.     } 
  25.  

運(yùn)行輸出

  1. Thread[main,5,main] logService.log start,1595223990417 
  2. Thread[main,5,main] logService.log end,1595223990432 
  3. Thread[SimpleAsyncTaskExecutor-1,5,main]開始記錄日志,1595223990443 
  4. Thread[SimpleAsyncTaskExecutor-1,5,main]日志記錄完畢,1595223992443 

前2行輸出,可以看出logService.log立即就返回了,后面2行來自于log方法,相差2秒左右。

前面2行在主線程中執(zhí)行,后面2行在異步線程中執(zhí)行。

5、獲取異步返回值

用法

若需取異步執(zhí)行結(jié)果,方法返回值必須為Future類型,使用spring提供的靜態(tài)方法org.springframework.scheduling.annotation.AsyncResult#forValue創(chuàng)建返回值,如:

  1. public Future<String> getGoodsInfo(long goodsId) throws InterruptedException { 
  2.     return AsyncResult.forValue(String.format("商品%s基本信息!", goodsId)); 

案例

場景:電商中商品詳情頁通常會(huì)有很多信息:商品基本信息、商品描述信息、商品評(píng)論信息,通過3個(gè)方法來或者這幾個(gè)信息。

這3個(gè)方法之間無關(guān)聯(lián),所以可以采用異步的方式并行獲取,提升效率。

下面是商品服務(wù),內(nèi)部3個(gè)方法都需要異步,所以直接在類上使用@Async標(biāo)注了,每個(gè)方法內(nèi)部休眠500毫秒,模擬一下耗時(shí)操作。

  1. package com.javacode2018.async.demo2; 
  2.  
  3. import org.springframework.scheduling.annotation.Async; 
  4. import org.springframework.scheduling.annotation.AsyncResult; 
  5. import org.springframework.stereotype.Component; 
  6.  
  7. import java.util.Arrays; 
  8. import java.util.List; 
  9. import java.util.concurrent.Future; 
  10. import java.util.concurrent.TimeUnit; 
  11.  
  12. @Async 
  13. @Component 
  14. public class GoodsService { 
  15.     //模擬獲取商品基本信息,內(nèi)部耗時(shí)500毫秒 
  16.     public Future<String> getGoodsInfo(long goodsId) throws InterruptedException { 
  17.         TimeUnit.MILLISECONDS.sleep(500); 
  18.         return AsyncResult.forValue(String.format("商品%s基本信息!", goodsId)); 
  19.     } 
  20.  
  21.     //模擬獲取商品描述信息,內(nèi)部耗時(shí)500毫秒 
  22.     public Future<String> getGoodsDesc(long goodsId) throws InterruptedException { 
  23.         TimeUnit.MILLISECONDS.sleep(500); 
  24.         return AsyncResult.forValue(String.format("商品%s描述信息!", goodsId)); 
  25.     } 
  26.  
  27.     //模擬獲取商品評(píng)論信息列表,內(nèi)部耗時(shí)500毫秒 
  28.     public Future<List<String>> getGoodsComments(long goodsId) throws InterruptedException { 
  29.         TimeUnit.MILLISECONDS.sleep(500); 
  30.         List<String> comments = Arrays.asList("評(píng)論1""評(píng)論2"); 
  31.         return AsyncResult.forValue(comments); 
  32.     } 

來個(gè)spring配置類,需要加上@EnableAsync開啟bean方法的異步調(diào)用.

  1. package com.javacode2018.async.demo2; 
  2.  
  3. import org.springframework.context.annotation.ComponentScan; 
  4. import org.springframework.scheduling.annotation.EnableAsync; 
  5.  
  6. @ComponentScan 
  7. @EnableAsync 
  8. public class MainConfig2 { 

測試代碼

  1. @Test 
  2. public void test2() throws InterruptedException, ExecutionException { 
  3.     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 
  4.     context.register(MainConfig2.class); 
  5.     context.refresh(); 
  6.     GoodsService goodsService = context.getBean(GoodsService.class); 
  7.  
  8.     long starTime = System.currentTimeMillis(); 
  9.     System.out.println("開始獲取商品的各種信息"); 
  10.  
  11.     long goodsId = 1L; 
  12.     Future<String> goodsInfoFuture = goodsService.getGoodsInfo(goodsId); 
  13.     Future<String> goodsDescFuture = goodsService.getGoodsDesc(goodsId); 
  14.     Future<List<String>> goodsCommentsFuture = goodsService.getGoodsComments(goodsId); 
  15.  
  16.     System.out.println(goodsInfoFuture.get()); 
  17.     System.out.println(goodsDescFuture.get()); 
  18.     System.out.println(goodsCommentsFuture.get()); 
  19.  
  20.     System.out.println("商品信息獲取完畢,總耗時(shí)(ms):" + (System.currentTimeMillis() - starTime)); 
  21.  
  22.     //休眠一下,防止@Test退出 
  23.     TimeUnit.SECONDS.sleep(3); 

運(yùn)行輸出

  1. 開始獲取商品的各種信息 
  2. 商品1基本信息! 
  3. 商品1描述信息! 
  4. [評(píng)論1, 評(píng)論2
  5. 商品信息獲取完畢,總耗時(shí)(ms):525 

3個(gè)方法總計(jì)耗時(shí)500毫秒左右。

如果不采用異步的方式,3個(gè)方法會(huì)同步執(zhí)行,耗時(shí)差不多1.5秒,來試試,將GoodsService上的@Async去掉,然后再次執(zhí)行測試案例,輸出

  1. 開始獲取商品的各種信息 
  2. 商品1基本信息! 
  3. 商品1描述信息! 
  4. [評(píng)論1, 評(píng)論2
  5. 商品信息獲取完畢,總耗時(shí)(ms):1503 

這個(gè)案例大家可以借鑒一下,按照這個(gè)思路可以去優(yōu)化一下你們的代碼,方法之間無關(guān)聯(lián)的可以采用異步的方式,并行去獲取,最終耗時(shí)為最長的那個(gè)方法,整體相對(duì)于同步的方式性能提升不少。

6、自定義異步執(zhí)行的線程池

默認(rèn)情況下,@EnableAsync使用內(nèi)置的線程池來異步調(diào)用方法,不過我們也可以自定義異步執(zhí)行任務(wù)的線程池。

有2種方式來自定義異步處理的線程池

方式1

在spring容器中定義一個(gè)線程池類型的bean,bean名稱必須是taskExecutor

  1. @Bean 
  2. public Executor taskExecutor() { 
  3.     ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
  4.     executor.setCorePoolSize(10); 
  5.     executor.setMaxPoolSize(100); 
  6.     executor.setThreadNamePrefix("my-thread-"); 
  7.     return executor; 

方式2

定義一個(gè)bean,實(shí)現(xiàn)AsyncConfigurer接口中的getAsyncExecutor方法,這個(gè)方法需要返回自定義的線程池,案例代碼:

  1. package com.javacode2018.async.demo3; 
  2.  
  3. import com.javacode2018.async.demo1.LogService; 
  4. import org.springframework.beans.factory.annotation.Qualifier; 
  5. import org.springframework.context.annotation.Bean; 
  6. import org.springframework.lang.Nullable; 
  7. import org.springframework.scheduling.annotation.AsyncConfigurer; 
  8. import org.springframework.scheduling.annotation.EnableAsync; 
  9. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 
  10.  
  11. import java.util.concurrent.Executor; 
  12.  
  13. @EnableAsync 
  14. public class MainConfig3 { 
  15.  
  16.     @Bean 
  17.     public LogService logService() { 
  18.         return new LogService(); 
  19.     } 
  20.  
  21.     /** 
  22.      * 定義一個(gè)AsyncConfigurer類型的bean,實(shí)現(xiàn)getAsyncExecutor方法,返回自定義的線程池 
  23.      * 
  24.      * @param executor 
  25.      * @return 
  26.      */ 
  27.     @Bean 
  28.     public AsyncConfigurer asyncConfigurer(@Qualifier("logExecutors") Executor executor) { 
  29.         return new AsyncConfigurer() { 
  30.             @Nullable 
  31.             @Override 
  32.             public Executor getAsyncExecutor() { 
  33.                 return executor; 
  34.             } 
  35.         }; 
  36.     } 
  37.  
  38.     /** 
  39.      * 定義一個(gè)線程池,用來異步處理日志方法調(diào)用 
  40.      * 
  41.      * @return 
  42.      */ 
  43.     @Bean 
  44.     public Executor logExecutors() { 
  45.         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
  46.         executor.setCorePoolSize(10); 
  47.         executor.setMaxPoolSize(100); 
  48.         //線程名稱前綴 
  49.         executor.setThreadNamePrefix("log-thread-"); //@1 
  50.         return executor; 
  51.     } 
  52.  

@1自定義的線程池中線程名稱前綴為log-thread-,運(yùn)行下面測試代碼

  1. @Test 
  2. public void test3() throws InterruptedException { 
  3.     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 
  4.     context.register(MainConfig3.class); 
  5.     context.refresh(); 
  6.     LogService logService = context.getBean(LogService.class); 
  7.     System.out.println(Thread.currentThread() + " logService.log start," + System.currentTimeMillis()); 
  8.     logService.log("異步執(zhí)行方法!"); 
  9.     System.out.println(Thread.currentThread() + " logService.log end," + System.currentTimeMillis()); 
  10.  
  11.     //休眠一下,防止@Test退出 
  12.     TimeUnit.SECONDS.sleep(3); 

輸出

  1. Thread[main,5,main] logService.log start,1595228732914 
  2. Thread[main,5,main] logService.log end,1595228732921 
  3. Thread[log-thread-1,5,main]開始記錄日志,1595228732930 
  4. Thread[log-thread-1,5,main]日志記錄完畢,1595228734931 

最后2行日志中線程名稱是log-thread-,正是我們自定義線程池中的線程。

7、自定義異常處理

異步方法若發(fā)生了異常,我們?nèi)绾潍@取異常信息呢?此時(shí)可以通過自定義異常處理來解決。

異常處理分2種情況

  1. 當(dāng)返回值是Future的時(shí)候,方法內(nèi)部有異常的時(shí)候,異常會(huì)向外拋出,可以對(duì)Future.get采用try..catch來捕獲異常
  2. 當(dāng)返回值不是Future的時(shí)候,可以自定義一個(gè)bean,實(shí)現(xiàn)AsyncConfigurer接口中的getAsyncUncaughtExceptionHandler方法,返回自定義的異常處理器

情況1:返回值為Future類型

用法

通過try..catch來捕獲異常,如下

  1. try { 
  2.     Future<String> future = logService.mockException(); 
  3.     System.out.println(future.get()); 
  4. catch (ExecutionException e) { 
  5.     System.out.println("捕獲 ExecutionException 異常"); 
  6.     //通過e.getCause獲取實(shí)際的異常信息 
  7.     e.getCause().printStackTrace(); 
  8. catch (InterruptedException e) { 
  9.     e.printStackTrace(); 

案例

LogService中添加一個(gè)方法,返回值為Future,內(nèi)部拋出一個(gè)異常,如下:

  1. @Async 
  2. public Future<String> mockException() { 
  3.     //模擬拋出一個(gè)異常 
  4.     throw new IllegalArgumentException("參數(shù)有誤!"); 

測試代碼如下

  1. @Test 
  2. public void test5() throws InterruptedException { 
  3.     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 
  4.     context.register(MainConfig1.class); 
  5.     context.refresh(); 
  6.     LogService logService = context.getBean(LogService.class); 
  7.     try { 
  8.         Future<String> future = logService.mockException(); 
  9.         System.out.println(future.get()); 
  10.     } catch (ExecutionException e) { 
  11.         System.out.println("捕獲 ExecutionException 異常"); 
  12.         //通過e.getCause獲取實(shí)際的異常信息 
  13.         e.getCause().printStackTrace(); 
  14.     } catch (InterruptedException e) { 
  15.         e.printStackTrace(); 
  16.     } 
  17.     //休眠一下,防止@Test退出 
  18.     TimeUnit.SECONDS.sleep(3); 

運(yùn)行輸出

  1. java.lang.IllegalArgumentException: 參數(shù)有誤! 
  2. 捕獲 ExecutionException 異常 
  3.  at com.javacode2018.async.demo1.LogService.mockException(LogService.java:23
  4.  at com.javacode2018.async.demo1.LogService$$FastClassBySpringCGLIB$$32a28430.invoke(<generated>) 
  5.  at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218

情況2:無返回值異常處理

用法

當(dāng)返回值不是Future的時(shí)候,可以自定義一個(gè)bean,實(shí)現(xiàn)AsyncConfigurer接口中的getAsyncUncaughtExceptionHandler方法,返回自定義的異常處理器,當(dāng)目標(biāo)方法執(zhí)行過程中拋出異常的時(shí)候,此時(shí)會(huì)自動(dòng)回調(diào)AsyncUncaughtExceptionHandler#handleUncaughtException這個(gè)方法,可以在這個(gè)方法中處理異常,如下:

  1. @Bean 
  2. public AsyncConfigurer asyncConfigurer() { 
  3.     return new AsyncConfigurer() { 
  4.         @Nullable 
  5.         @Override 
  6.         public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { 
  7.             return new AsyncUncaughtExceptionHandler() { 
  8.                 @Override 
  9.                 public void handleUncaughtException(Throwable ex, Method method, Object... params) { 
  10.                     //當(dāng)目標(biāo)方法執(zhí)行過程中拋出異常的時(shí)候,此時(shí)會(huì)自動(dòng)回調(diào)這個(gè)方法,可以在這個(gè)方法中處理異常 
  11.                 } 
  12.             }; 
  13.         } 
  14.     }; 

案例

LogService中添加一個(gè)方法,內(nèi)部拋出一個(gè)異常,如下:

  1. @Async 
  2. public void mockNoReturnException() { 
  3.     //模擬拋出一個(gè)異常 
  4.     throw new IllegalArgumentException("無返回值的異常!"); 

來個(gè)spring配置類,通過AsyncConfigurer來自定義異常處理器AsyncUncaughtExceptionHandler

  1. package com.javacode2018.async.demo4; 
  2.  
  3. import com.javacode2018.async.demo1.LogService; 
  4. import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; 
  5. import org.springframework.context.annotation.Bean; 
  6. import org.springframework.lang.Nullable; 
  7. import org.springframework.scheduling.annotation.AsyncConfigurer; 
  8. import org.springframework.scheduling.annotation.EnableAsync; 
  9.  
  10. import java.lang.reflect.Method; 
  11. import java.util.Arrays; 
  12.  
  13. @EnableAsync 
  14. public class MainConfig4 { 
  15.  
  16.     @Bean 
  17.     public LogService logService() { 
  18.         return new LogService(); 
  19.     } 
  20.  
  21.     @Bean 
  22.     public AsyncConfigurer asyncConfigurer() { 
  23.         return new AsyncConfigurer() { 
  24.             @Nullable 
  25.             @Override 
  26.             public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { 
  27.                 return new AsyncUncaughtExceptionHandler() { 
  28.                     @Override 
  29.                     public void handleUncaughtException(Throwable ex, Method method, Object... params) { 
  30.                         String msg = String.format("方法[%s],參數(shù)[%s],發(fā)送異常了,異常詳細(xì)信息:", method, Arrays.asList(params)); 
  31.                         System.out.println(msg); 
  32.                         ex.printStackTrace(); 
  33.                     } 
  34.                 }; 
  35.             } 
  36.         }; 
  37.     } 
  38.  

運(yùn)行輸出

  1. 方法[public void com.javacode2018.async.demo1.LogService.mockNoReturnException()],參數(shù)[[]],發(fā)送異常了,異常詳細(xì)信息: 
  2. java.lang.IllegalArgumentException: 無返回值的異常! 
  3.  at com.javacode2018.async.demo1.LogService.mockNoReturnException(LogService.java:29
  4.  at com.javacode2018.async.demo1.LogService$$FastClassBySpringCGLIB$$32a28430.invoke(<generated>) 
  5.  at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218

8、線程池隔離

什么是線程池隔離?

一個(gè)系統(tǒng)中可能有很多業(yè)務(wù),比如充值服務(wù)、提現(xiàn)服務(wù)或者其他服務(wù),這些服務(wù)中都有一些方法需要異步執(zhí)行,默認(rèn)情況下他們會(huì)使用同一個(gè)線程池去執(zhí)行,如果有一個(gè)業(yè)務(wù)量比較大,占用了線程池中的大量線程,此時(shí)會(huì)導(dǎo)致其他業(yè)務(wù)的方法無法執(zhí)行,那么我們可以采用線程隔離的方式,對(duì)不同的業(yè)務(wù)使用不同的線程池,相互隔離,互不影響。

@Async注解有個(gè)value參數(shù),用來指定線程池的bean名稱,方法運(yùn)行的時(shí)候,就會(huì)采用指定的線程池來執(zhí)行目標(biāo)方法。

使用步驟

  1. 在spring容器中,自定義線程池相關(guān)的bean
  2. @Async("線程池bean名稱")

案例

模擬2個(gè)業(yè)務(wù):異步充值、異步提現(xiàn);2個(gè)業(yè)務(wù)都采用獨(dú)立的線程池來異步執(zhí)行,互不影響。

異步充值服務(wù)
  1. package com.javacode2018.async.demo5; 
  2.  
  3. import org.springframework.scheduling.annotation.Async; 
  4. import org.springframework.stereotype.Component; 
  5.  
  6. @Component 
  7. public class RechargeService { 
  8.     //模擬異步充值 
  9.     @Async(MainConfig5.RECHARGE_EXECUTORS_BEAN_NAME) 
  10.     public void recharge() { 
  11.         System.out.println(Thread.currentThread() + "模擬異步充值"); 
  12.     } 
異步提現(xiàn)服務(wù)
  1. package com.javacode2018.async.demo5; 
  2.  
  3. import org.springframework.scheduling.annotation.Async; 
  4. import org.springframework.stereotype.Component; 
  5.  
  6. @Component 
  7. public class CashOutService { 
  8.     //模擬異步提現(xiàn) 
  9.     @Async(MainConfig5.CASHOUT_EXECUTORS_BEAN_NAME) 
  10.     public void cashOut() { 
  11.         System.out.println(Thread.currentThread() + "模擬異步提現(xiàn)"); 
  12.     } 
spring配置類

注意@0、@1、@2、@3、@4這幾個(gè)地方的代碼,采用線程池隔離的方式,注冊了2個(gè)線程池,分別用來處理上面的2個(gè)異步業(yè)務(wù)。

  1. package com.javacode2018.async.demo5; 
  2.  
  3. import org.springframework.context.annotation.Bean; 
  4. import org.springframework.context.annotation.ComponentScan; 
  5. import org.springframework.scheduling.annotation.EnableAsync; 
  6. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 
  7.  
  8. import java.util.concurrent.Executor; 
  9.  
  10. @EnableAsync //@0:啟用方法異步調(diào)用 
  11. @ComponentScan 
  12. public class MainConfig5 { 
  13.  
  14.     //@1:值業(yè)務(wù)線程池bean名稱 
  15.     public static final String RECHARGE_EXECUTORS_BEAN_NAME = "rechargeExecutors"
  16.     //@2:提現(xiàn)業(yè)務(wù)線程池bean名稱 
  17.     public static final String CASHOUT_EXECUTORS_BEAN_NAME = "cashOutExecutors"
  18.  
  19.     /** 
  20.      * @3:充值的線程池,線程名稱以recharge-thread-開頭 
  21.      * @return 
  22.      */ 
  23.     @Bean(RECHARGE_EXECUTORS_BEAN_NAME) 
  24.     public Executor rechargeExecutors() { 
  25.         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
  26.         executor.setCorePoolSize(10); 
  27.         executor.setMaxPoolSize(100); 
  28.         //線程名稱前綴 
  29.         executor.setThreadNamePrefix("recharge-thread-"); 
  30.         return executor; 
  31.     } 
  32.  
  33.     /** 
  34.      * @4: 充值的線程池,線程名稱以cashOut-thread-開頭 
  35.      * 
  36.      * @return 
  37.      */ 
  38.     @Bean(CASHOUT_EXECUTORS_BEAN_NAME) 
  39.     public Executor cashOutExecutors() { 
  40.         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
  41.         executor.setCorePoolSize(10); 
  42.         executor.setMaxPoolSize(100); 
  43.         //線程名稱前綴 
  44.         executor.setThreadNamePrefix("cashOut-thread-"); 
  45.         return executor; 
  46.     } 
測試代碼
  1. @Test 
  2. public void test7() throws InterruptedException { 
  3.     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 
  4.     context.register(MainConfig5.class); 
  5.     context.refresh(); 
  6.  
  7.     RechargeService rechargeService = context.getBean(RechargeService.class); 
  8.     rechargeService.recharge(); 
  9.     CashOutService cashOutService = context.getBean(CashOutService.class); 
  10.     cashOutService.cashOut(); 
  11.  
  12.     //休眠一下,防止@Test退出 
  13.     TimeUnit.SECONDS.sleep(3); 
運(yùn)行輸出
  1. Thread[recharge-thread-1,5,main]模擬異步充值 
  2. Thread[cashOut-thread-1,5,main]模擬異步提現(xiàn) 

輸出中可以看出2個(gè)業(yè)務(wù)使用的是不同的線程池執(zhí)行的。

9、源碼 & 原理

內(nèi)部使用aop實(shí)現(xiàn)的,@EnableAsync會(huì)引入一個(gè)bean后置處理器:AsyncAnnotationBeanPostProcessor,將其注冊到spring容器,這個(gè)bean后置處理器在所有bean創(chuàng)建過程中,判斷bean的類上是否有@Async注解或者類中是否有@Async標(biāo)注的方法,如果有,會(huì)通過aop給這個(gè)bean生成代理對(duì)象,會(huì)在代理對(duì)象中添加一個(gè)切面:org.springframework.scheduling.annotation.AsyncAnnotationAdvisor,這個(gè)切面中會(huì)引入一個(gè)攔截器:AnnotationAsyncExecutionInterceptor,方法異步調(diào)用的關(guān)鍵代碼就是在這個(gè)攔截器的invoke方法中實(shí)現(xiàn)的,可以去看一下。

責(zé)任編輯:張燕妮 來源: 今日頭條
相關(guān)推薦

2020-03-26 12:38:15

代碼節(jié)點(diǎn)數(shù)據(jù)

2022-09-09 09:33:14

支付寶代碼性能

2020-07-21 15:40:55

NginxJava服務(wù)器

2024-12-13 13:58:53

2011-07-01 10:11:39

2024-07-17 08:25:44

2014-03-26 10:00:06

RailsRails性能

2024-10-29 08:21:05

2021-12-29 11:06:25

Java代碼技巧

2014-07-31 09:35:57

2019-09-26 08:33:51

Nginx技術(shù)Java

2018-08-23 17:45:52

2013-04-01 00:16:41

飛魚星無線云無線AP

2021-04-21 18:57:16

二進(jìn)制存儲(chǔ)空間

2017-12-13 13:09:36

NginxWeb應(yīng)用

2023-06-13 13:52:00

Java 7線程池

2018-10-07 05:27:03

Python代碼機(jī)器學(xué)習(xí)

2017-09-26 14:56:57

MongoDBLBS服務(wù)性能

2025-04-07 02:22:00

C#性能優(yōu)化

2020-08-10 11:00:02

Python優(yōu)化代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)