激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

服務器之家 - 編程語言 - Java教程 - Spring之兩種任務調度Scheduled和Async詳解

Spring之兩種任務調度Scheduled和Async詳解

2022-02-22 00:39slimer Java教程

這篇文章主要介紹了Spring之兩種任務調度Scheduled和Async,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

1、Spring調度的兩種方式

Spring提供了兩種后臺任務的方法,分別是:

  • 調度任務,@Schedule
  • 異步任務,@Async

當然,使用這兩個是有條件的,需要在spring應用的上下文中聲明

<task:annotation-driven/>當然,如果我們是基于java配置的,需要在配置哪里加多EnableScheduling和@EnableAsync 就像下面這樣

?
1
2
3
4
5
@EnableScheduling
@EnableAsync
public class WebAppConfig {
   ....

除此之外,還是有第三方庫可以調用的,例如Quartz.

2、@Schedule

先看下@Schedule怎么調用再說

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public final static long ONE_DAY = 24 * 60 * 60 * 1000;
public final static long ONE_HOUR = 60 * 60 * 1000;
 
@Scheduled(fixedRate = ONE_DAY)
public void scheduledTask() {
   System.out.println(" 我是一個每隔一天就會執行一次的調度任務");
}
 
@Scheduled(fixedDelay = ONE_HOURS)
public void scheduleTask2() {
    System.out.println(" 我是一個執行完后,隔一小時就會執行的任務");
}
 
@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {
    // something that should execute periodically
}
 
@Scheduled(cron = "0 0/1 * * * ? ")
public void ScheduledTask3() {
    System.out.println(" 我是一個每隔一分鐘就就會執行的任務");
}

需要注意的

  • 關于最后一個,在指定時間執行的任務,里面使用的是Cron表達式,同時我們看到了兩個不一樣的面孔fixedDelay& fixedRate,前者fixedDelay表示在指定間隔運行程序,例如這個程序在今晚九點運行程序,跑完這個方法后的一個小時,就會再執行一次,而后者fixedDelay者是指,這個函數每隔一段時間就會被調用(我們這里設置的是一天),不管再次調度的時候,這個方法是在運行還是結束了。而前者就要求是函數運行結束后開始計時的,這就是兩者區別。
  • 這個還有一個initialDelay的參數,是第一次調用前需要等待的時間,這里表示被調用后的,推遲一秒再執行,這適合一些特殊的情況。
  • 我們在serviceImpl類寫這些調度任務時候,也需要在這些我們定義的serviceInterface的借口中寫多這個接口,要不然會爆 but not found in any interface(s) for bean JDK proxy.Either pull the method up to an interface or

3、@Async

有時候我們會調用一些特殊的任務,任務會比較耗時,重要的是,我們不管他返回的后果。這時候我們就需要用這類的異步任務啦,調用后就讓他去跑,不堵塞主線程,我們繼續干別的。代碼像下面這樣:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void AsyncTask(){
    @Async
    public void doSomeHeavyBackgroundTask(int sleepTime) {
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }    
     
    @Async
    public Future<String> doSomeHeavyBackgroundTask() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
     
    public void printLog() {
         System.out.println(" i print a log ,time=" + System.currentTimeMillis());
    }
}

我們寫個簡單的測試類來測試下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = AsycnTaskConfig.class) //要聲明@EnableASync
public class AsyncTaskTest {
    @Autowired
    AsyncTask asyncTask;
    @Test
    public void AsyncTaskTest() throws InterruptedException {
        if (asyncTask != null) {
            asyncTask.doSomeHeavyBackgroundTask(4000);
            asyncTask.printLog();
            Thread.sleep(5000);
        }
    }
}

這感覺比我們手動開多一個線程方便多了,不想異步的話直接把@Async去掉就可以了,另外如果你想要返回個結果的,這需要加多個Future<>,關于這個Future,完全可以寫多幾篇文章介紹,順便把FutureTask介紹了。如果想修改Spring boot的默認線程池配置,可以實現AsyncConfigurer.

需要注意的:

相對于@scheduled,這個可以有參數和返回個結果,因為這個是我們調用的,而調度的任務是spring調用的。

異步方法不能內部調用,只能像上面那樣,外部調用,否則就會變成阻塞主線程的同步任務啦!這個坑我居然跳下去了!例如下面這樣的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void AsyncTask(){
    public void fakeAsyncTaskTest(){
        doSomeHeavyBackgroundTask(4000);
        printLog();
        //你會發現,當你像這樣內部調用的時候,居然是同步執行的,不是異步的!!
    }
     
    @Async
    public void doSomeHeavyBackgroundTask(int sleepTime) {
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
     
    public void printLog() {
        System.out.println(" i print a log ");
    }
}
  • 另外一點就是不要重復的掃描,這也會導致異步無效,具體的可以看這個stackoveflow的spring-async-not-working Issue。
  • 關于異常處理,難免在這個異步執行過程中有異常發生,對于這個問題,spring提供的解決方案如下,實現
?
1
2
3
4
5
6
7
AsyncUncaughtExceptionHandler接口。
public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
    @Override
    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        // handle exception
    }
}

寫好我們的異常處理后,我們需要配置一下,告訴spring,這個異常處理就是我們在運行異步任務時候,拋出錯誤時的異常終結者

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
    @Bean
    public AsyncTask asyncBean() {
        return new AsyncTask();
    }
     
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(7);
        executor.setMaxPoolSize(42);
        executor.setQueueCapacity(11);
        executor.setThreadNamePrefix("MyExecutor-");
        executor.initialize();
        return executor;
    }
     
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return new MyAsyncUncaughtExceptionHandler();
    }
}

4、Quartz登場

處理這兩個外,還有一個和spring整合的第三方庫叫Quartz

看了下官網的使用簡介,也是挺逗的,現在都習慣用maven,gradle之類來關系這些依賴了,他還叫人下載,也是不知為何,詳情點擊->http://quartz-scheduler.org/documentation/quartz-2.2.x/quick-start

估計有可能是因為沒再維護了的原因吧,看了下,最新版2.2居然是Sep, 2013更新的…

居然是停更的,不過Quartz作為一個企業級應用的任務調度框架,還是一個可以的候選項目的。

這里不鋪開講,有興趣就去官網看下吧。整體用起來感覺是沒有spring自己的后臺任務方便,不過也可以接受,只需要簡單的配置就可以使用了。

@Scheduled 和@Async的使用

如題,今天在知乎突然看到一份關于springboot自帶調度器的問題思考,有這么一段內容“在使用@Scheduled注解時,如果不自己重新配置調度器,那么就會使用默認的,從而會導致一些調度執行上的問題”;聯系到自己在程序中使用時沒有關注到這個問題,因此仔細測試研究一番,最終了解了其中的一些關鍵思想。

首先,需要了解@Scheduled 和@Async這倆注解的區別:

@Scheduled 任務調度注解,主要用于配置定時任務;springboot默認的調度器線程池大小為 1。

@Async 任務異步執行注解,主要用于方法上,表示當前方法會使用新線程異步執行;springboot默認執行器線程池大小為100。

所以,如果在使用springboot定時器時,如果有多個定時任務時,在使用默認的調度器配置,就會出現排隊現象,因為同時只能有一個任務在執行,這個時候當一個任務掛死,那后面的定時任務就不能有效執行了;

解決辦法就是自定義調度器,有兩種方式:

方法一:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
@Bean
  public TaskScheduler scheduledExecutorService() {
      ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
      scheduler.setPoolSize(10);
      scheduler.setThreadNamePrefix("scheduled-thread-");
      //設置線程池關閉的時候等待所有任務都完成再繼續銷毀其他的Bean
      scheduler.setWaitForTasksToCompleteOnShutdown(true);
      //設置線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住
      scheduler.setAwaitTerminationSeconds(60);
      //這里采用了CallerRunsPolicy策略,當線程池沒有處理能力的時候,該策略會直接在 execute 方法的調用線程中運行被拒絕的任務;如果執行程序已關閉,則會丟棄該任務
      scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
      return scheduler;
  }

方法二:

?
1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class ScheduledConfig implements SchedulingConfigurer {
 public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
 taskRegistrar.setScheduler(setExecutor());
 }
 
 @Bean(destroyMethod="shutdown")
 public Executor setExecutor(){
 return Executors.newScheduledThreadPool(10); // 10個線程來處理。
 }
}

上述自定義調度器的方式,會有一個問題:當有足夠的空余線程時,多任務時并行執行,但是同一定時任務仍會同步執行(當定時任務的執行時間大于每次執行的時間間隔時即可發現);

配合@Async 注解使用,這樣在每次執行定時任務時就新開一個線程,異步非阻塞運行;同時使用這兩個注解的效果,相當于@Scheduled僅僅負責調度,而@Async指定的executor負責任務執行,不再使用調度器中的執行器來執行任務(由實際測試結果來猜測的,并沒有找到對應的源碼邏輯,待后續補充)。

自定義執行器配置如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Bean("taskExecutor")
 public ThreadPoolTaskExecutor taskExecutor(){
     ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
     executor.setCorePoolSize(corePoolSize);
     executor.setMaxPoolSize(maxPoolSize);
     executor.setQueueCapacity(queueCapacity);
     executor.setKeepAliveSeconds(keepAliveTime);
     executor.setThreadNamePrefix(threadNamePrefix);
     // 線程池對拒絕任務的處理策略
     executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
     // 初始化
     executor.initialize();
     return executor;
 }

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://www.cnblogs.com/slimer/p/6401394.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久午夜神器 | 国产精品99久久久久久久vr | 福利四区| 日本爽快片100色毛片视频 | 国产精品久久久av | 欧美成人一区二区视频 | 国产资源在线视频 | 羞羞的视频免费在线观看 | 国产精品午夜在线 | 成人区一区二区三区 | 亚洲一区二区三区91 | 成人午夜免费在线观看 | 伊人午夜视频 | 极品销魂一区二区三区 | 99一区二区| 欧美老外a级毛片 | 欧美激情天堂 | 中文字幕 亚洲一区 | 把娇妻调教成暴露狂 | 免费观看又色又爽又黄的崩锅 | 精品国产一级毛片 | 成人毛片视频免费看 | 欧美 国产 亚洲 卡通 综合 | 欧美日韩高清不卡 | 国产69精品99久久久久久宅男 | www.9191.com| 日本网站一区二区三区 | 国产91成人 | 日本视频在线播放 | 久国久产久精永久网页 | 欧美精品成人一区二区在线观看 | 国产午夜亚洲精品理论片大丰影院 | 国产精品一区在线免费观看 | 日韩av成人 | 2021年无线乱码播放高清完整 | 国产精品啪一品二区三区粉嫩 | 国产在线一区二区三区 | 欧美人与性禽动交精品 | 一级毛片播放 | 欧美日韩专区国产精品 | 亚洲码无人客一区二区三区 |