国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring Boot利用@Async異步調(diào)用:ThreadPoolTaskScheduler線程池的優(yōu)雅關閉詳解

Spring Boot利用@Async異步調(diào)用:ThreadPoolTaskScheduler線程池的優(yōu)雅關閉詳解

2021-04-25 11:35翟永超 Java教程

這篇文章主要給大家介紹了關于Spring Boot利用@Async異步調(diào)用:ThreadPoolTaskScheduler線程池的優(yōu)雅關閉的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧

前言

之前分享了一篇關于Spring Boot中使用@Async來實現(xiàn)異步任務和線程池控制的文章:《Spring Boot使用@Async實現(xiàn)異步調(diào)用:自定義線程池》。由于最近身邊也發(fā)現(xiàn)了不少異步任務沒有正確處理而導致的不少問題,所以在本文就接前面內(nèi)容,繼續(xù)說說線程池的優(yōu)雅關閉,主要針對ThreadPoolTaskScheduler線程池。

問題現(xiàn)象

在上篇文章的例子Chapter4-1-3中,我們定義了一個線程池,然后利用@Async注解寫了3個任務,并指定了這些任務執(zhí)行使用的線程池。在上文的單元測試中,我們沒有具體說說shutdown相關的問題,下面我們就來模擬一個問題現(xiàn)場出來。

第一步:如前文一樣,我們定義一個ThreadPoolTaskScheduler線程池:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootApplication
public class Application {
 public static void main(String[] args) {
 SpringApplication.run(Application.class, args);
 }
 
 @EnableAsync
 @Configuration
 class TaskPoolConfig {
 @Bean("taskExecutor")
 public Executor taskExecutor() {
  ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
  executor.setPoolSize(20);
  executor.setThreadNamePrefix("taskExecutor-");
  return executor;
 }
 }
}

第二步:改造之前的異步任務,讓它依賴一個外部資源,比如:Redis

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Slf4j
@Component
public class Task {
 
 @Autowired
 private StringRedisTemplate stringRedisTemplate;
 @Async("taskExecutor")
 public void doTaskOne() throws Exception {
 log.info("開始做任務一");
 long start = System.currentTimeMillis();
 log.info(stringRedisTemplate.randomKey());
 long end = System.currentTimeMillis();
 log.info("完成任務一,耗時:" + (end - start) + "毫秒");
 }
 
 @Async("taskExecutor")
 public void doTaskTwo() throws Exception {
 log.info("開始做任務二");
 long start = System.currentTimeMillis();
 log.info(stringRedisTemplate.randomKey());
 long end = System.currentTimeMillis();
 log.info("完成任務二,耗時:" + (end - start) + "毫秒");
 }
 
 @Async("taskExecutor")
 public void doTaskThree() throws Exception {
 log.info("開始做任務三");
 long start = System.currentTimeMillis();
 log.info(stringRedisTemplate.randomKey());
 long end = System.currentTimeMillis();
 log.info("完成任務三,耗時:" + (end - start) + "毫秒");
 }
}

注意:這里省略了pom.xml中引入依賴和配置redis的步驟

第三步:修改單元測試,模擬高并發(fā)情況下ShutDown的情況:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ApplicationTests {
 @Autowired
 private Task task;
 @Test
 @SneakyThrows
 public void test() {
 for (int i = 0; i < 10000; i++) {
  task.doTaskOne();
  task.doTaskTwo();
  task.doTaskThree();
 
  if (i == 9999) {
  System.exit(0);
  }
 }
 }
}

說明:通過for循環(huán)往上面定義的線程池中提交任務,由于是異步執(zhí)行,在執(zhí)行過程中,利用System.exit(0)來關閉程序,此時由于有任務在執(zhí)行,就可以觀察這些異步任務的銷毀與Spring容器中其他資源的順序是否安全。

第四步:運行上面的單元測試,我們將碰到下面的異常內(nèi)容。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
 at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:204) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:348) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:129) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:92) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:79) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:194) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:169) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at org.springframework.data.redis.core.RedisTemplate.randomKey(RedisTemplate.java:781) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 at com.didispace.async.Task.doTaskOne(Task.java:26) ~[classes/:na]
 at com.didispace.async.Task$$FastClassBySpringCGLIB$$ca3ff9d6.invoke(<generated>) ~[classes/:na]
 at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.14.RELEASE.jar:4.3.14.RELEASE]
 at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.14.RELEASE.jar:4.3.14.RELEASE]
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.14.RELEASE.jar:4.3.14.RELEASE]
 at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115) ~[spring-aop-4.3.14.RELEASE.jar:4.3.14.RELEASE]
 at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_151]
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_151]
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_151]
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_151]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_151]
 at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151]
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
 at redis.clients.util.Pool.getResource(Pool.java:53) ~[jedis-2.9.0.jar:na]
 at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226) ~[jedis-2.9.0.jar:na]
 at redis.clients.jedis.JedisPool.getResource(JedisPool.java:16) ~[jedis-2.9.0.jar:na]
 at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:194) ~[spring-data-redis-1.8.10.RELEASE.jar:na]
 ... 19 common frames omitted
Caused by: java.lang.InterruptedException: null
 at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014) ~[na:1.8.0_151]
 at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2088) ~[na:1.8.0_151]
 at org.apache.commons.pool2.impl.LinkedBlockingDeque.pollFirst(LinkedBlockingDeque.java:635) ~[commons-pool2-2.4.3.jar:2.4.3]
 at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:442) ~[commons-pool2-2.4.3.jar:2.4.3]
 at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:361) ~[commons-pool2-2.4.3.jar:2.4.3]
 at redis.clients.util.Pool.getResource(Pool.java:49) ~[jedis-2.9.0.jar:na]
 ... 22 common frames omitted

如何解決

原因分析

從異常信息JedisConnectionException: Could not get a resource from the pool來看,我們很容易的可以想到,在應用關閉的時候異步任務還在執(zhí)行,由于Redis連接池先銷毀了,導致異步任務中要訪問Redis的操作就報了上面的錯。所以,我們得出結論,上面的實現(xiàn)方式在應用關閉的時候是不優(yōu)雅的,那么我們要怎么做呢?

解決方法

要解決上面的問題很簡單,Spring的ThreadPoolTaskScheduler為我們提供了相關的配置,只需要加入如下設置即可:

?
1
2
3
4
5
6
7
8
9
@Bean("taskExecutor")
public Executor taskExecutor() {
 ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
 executor.setPoolSize(20);
 executor.setThreadNamePrefix("taskExecutor-");
 executor.setWaitForTasksToCompleteOnShutdown(true);
 executor.setAwaitTerminationSeconds(60);
 return executor;
}

說明:setWaitForTasksToCompleteOnShutdown(true)該方法就是這里的關鍵,用來設置線程池關閉的時候等待所有任務都完成再繼續(xù)銷毀其他的Bean,這樣這些異步任務的銷毀就會先于Redis線程池的銷毀。同時,這里還設置了setAwaitTerminationSeconds(60),該方法用來設置線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住。

完整示例:

讀者可以根據(jù)喜好選擇下面的兩個倉庫中查看Chapter4-1-4項目:

Github:https://github.com/dyc87112/SpringBoot-Learning/

Gitee:https://gitee.com/didispace/SpringBoot-Learning/

總結

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:http://blog.didispace.com/springbootasync-3/

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 欧美激情精品久久久久久变态 | 亚洲一区中文字幕在线观看 | 粉色在线观看 | 久草免费在线 | 国产资源在线观看视频 | 亚洲成人中文字幕 | www.日韩| 夜夜摸夜夜操 | av大片网| 中文字幕91 | 性免费网站 | 麻豆二区 | 一级黄片毛片 | 欧美久久久久 | 日韩精品久久 | 黄色小网站在线观看 | 日本高清视频在线播放 | 精品国产欧美一区二区三区成人 | 在线看国产 | 欧美激情一区二区三级高清视频 | 久久的爱 | 精品国产不卡一区二区三区 | 精彩视频一区二区三区 | 国产精品久久久久久久久免费桃花 | 亚洲午夜av| 欧美一区二区三区在线观看视频 | 精品1区| 一区二区三区在线不卡 | 成人免费视频在线观看 | 欧美一级免费 | 99re免费视频精品全部 | 亚洲免费观看在线视频 | 亚洲欧洲精品视频在线观看 | 国产日韩欧美一区二区 | 亚洲免费视频观看 | 亚州男人天堂 | 自拍偷拍小视频 | 久久久综合视频 | 久久久中文 | 在线a电影 | 操操操操操操 |