2017-07-18 64 views
3

我有多個組件,其中有@Scheduled註釋,並且我看到Spring一次只啓動一個組件,即使它們計劃在同一時間運行。在自己的線程中運行每個Spring Scheduler

我的用例如下。我希望每個@Scheduled註釋在其自己的線程中運行,但每個線程只能運行一次。

鑑於這種僞代碼與兩個調度:

@Scheduled(cron = "0 * * * * *") //run every minute 
public void methodA() { 
    log.info("Running method A"); 
    executeLongRunningJob("Finished method A"); 
} 

@Scheduled(cron = "0 * * * * *") //run every minute 
public void methodB() { 
    log.info("Running method B"); 
    executeLongRunningJob("Finished method B");  
} 

private void executeLongRunningJob(String msg) { 
    Thread.sleep(70 seconds); 
    System.out.println(msg); 
} 

注意任務花費的時間比調度計劃運行更長的時間。這是至關重要的。我不希望調度程序在完成運行之前再次啓動。

運行這段代碼的開箱給我這樣的輸出:

Running method A 
Finished method A 
Running method B 
Finished method B 
Running method A 
Finished method A 
Running method B 
Finished method B 
... and so on 

所以,很顯然它在一個單獨的線程同時運行調度。


當我把@Async我的便宜的方法,然後我幾乎得到正確的行爲,除了昂貴的方法,新的調度開始之前還沒有完成。

Running method A 
Running method B 
Running method A 
Running method B 
Finished method A 
Finished method B 
... and so on 

我想是這樣的輸出:

Running method A 
Running method B 
Finished method A 
Finished method B 
Running method A 
Running method B 
Finished method A 
Finished method B 
... and so on 

我怎樣才能做到這一點? 我希望每個調度程序能夠同時運行,但請等到它完成後再允許再次運行。 請記住,我有兩個以上的調度程序在相同的時間運行,有時甚至是不同的時間。

+0

'Executor'用'synchronize'可以幫助 – Ashish

回答

5

您是對的 - 默認情況下,調度程序使用大小爲1的線程池,因此每個任務都按順序處理。你可以通過配置TaskScheduler bean來獲得所需的池大小。考慮下面的例子:

import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.context.annotation.Bean; 
import org.springframework.scheduling.TaskScheduler; 
import org.springframework.scheduling.annotation.EnableScheduling; 
import org.springframework.scheduling.annotation.Scheduled; 
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 

import java.util.Date; 

@SpringBootApplication 
@EnableScheduling 
public class Application { 

    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 
    } 

    @Bean 
    public TaskScheduler taskScheduler() { 
     final ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); 
     scheduler.setPoolSize(10); 
     return scheduler; 
    } 


    @Scheduled(fixedDelay = 2 * 1000L, initialDelay = 3 * 1000L) 
    public void scheduled1() throws InterruptedException { 
     System.out.println(new Date() + " " + Thread.currentThread().getName() + ": scheduled1"); 
     Thread.sleep(1000); 
    } 

    @Scheduled(fixedDelay = 3 * 1000L, initialDelay = 3 * 1000L) 
    public void scheduled2() throws InterruptedException { 
     System.out.println(new Date() + " " + Thread.currentThread().getName() + ": scheduled2"); 
     Thread.sleep(1000); 
    } 
} 

它會在一個單獨的線程中運行的每個計劃的任務,例如:

Tue Jul 18 20:21:50 CEST 2017 taskScheduler-1: scheduled2 
Tue Jul 18 20:21:50 CEST 2017 taskScheduler-2: scheduled1 
Tue Jul 18 20:21:53 CEST 2017 taskScheduler-1: scheduled1 
Tue Jul 18 20:21:54 CEST 2017 taskScheduler-3: scheduled2 
Tue Jul 18 20:21:56 CEST 2017 taskScheduler-2: scheduled1 
Tue Jul 18 20:21:58 CEST 2017 taskScheduler-4: scheduled2 
Tue Jul 18 20:21:59 CEST 2017 taskScheduler-1: scheduled1 
+0

謝謝你的答案。一個問題。這個例子是否確保只有兩個調度程序同時運行。因此,計劃2將不會開始,直到計劃2的另一個完成? –

+0

我想我只需要確保池大小與調度程序的數量相同,並且應該沒問題?我證實了這一點,它的工作。 –

+0

沒錯:+1: –

相關問題