springboot 使用 @Scheduled 註解實現任務調度 以及相關踩坑記錄

關於spring boot 實現任務調度的方法有不少種,這裏再也不贅述。redis

首先pom只需引入spring

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>

而後application開啓@EnableScheduling架構

@SpringBootApplication
@EnableAsync
@EnableScheduling
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

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


}

以後用嘛就很簡單了app

@Component
@Configurable
public class TestONE {
    private Logger logger = (Logger) LoggerFactory.getLogger(TestONE.class);

    @Scheduled(cron = "0/5 * * * * ? ")
//    @Async
    public  void test1() {
        logger.error("任務1--開始");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.error("任務1---結束");
    }

========分隔線=========異步

首先大體說下遇到過的問題分佈式

Q1:啓動後修改本地時間可是調度任務再也不執行ide

  A:以前大體看了一下這塊的介紹,其實啓動以後虛擬機內維持一個時間計數器,這個是啓動時與系統時間同步過的,當讓會有一個專門管理調度任務的,按照虛擬機時間以及系統時間覈對(若是這出現不一致確定不執行了),若是一致那麼也知足cron規則就開啓執行。ui

Q2:出現漏執行的狀況.net

A:我目前瞭解到其實spring的@Scheduled默認是單線程的,也就是說一次只能執行一個定時任務,若是一但任務是耗時的那麼後面的自動進入線程的掛起等待隊列,固然這個隊列也是有大小限制,若是執行中任務特別耗時掛起的超過限制那麼後面的任務都不會執行。線程

        不少大企是很注重調度任務的可用性,由於畢竟對於任務調度這個事情來講裏面涉及到的業務確定都是有價值甚至很重要的。特別公司發展的必定程度調度任務的重要性很是的高。因此若是仍是單節點的架構的調度的話建議仍是上高可用的調度吧,那麼關於高可用的調度任務網上仍是有好幾個解決方案以供選擇,其實最核心的一點哪怕是多節點調度也是單一機器去執行調度任務,也就要求作到分佈式鎖,通常來說redis 或者 zookeeper就能夠很好的實現這塊。固然還有一個很重要的事兒就是關於調度任務失敗的重調。我的推薦elastic-job這個組件,能夠自行研究對比後選擇適合本身公司業務的。

        針對以上調度線程是單線程問題其實也能夠經過,設置執行線程數目,建議開啓的線程池核心線程不要太高,畢竟cpu也就那麼多個核心,線上項目又確定不是本身一個的。況且還有維護系統其餘組件等的線程。我的感受視本身項目裏調度數量和執行時間決定。單一時間段內不會出現跑滿便可。

/**
 * @author qiaolu
 */
@Configuration
public class ScheduledConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(setTaskExecutors());
    }

    @Bean
    public Executor setTaskExecutors() {
        return newScheduledThreadPool(2);
    }
}

固然針對耗時較長的調度任務其實完成能夠這樣解決:加上 @Async

spring會把這個方法另開啓一個線程去處理,以達到異步處理的效果,這樣調度任務也會快速。固然不必給全部調度都這麼加。

@Scheduled(cron = "0/5 * * * * ? ")
@Async
public  void test1() {
    logger.error("任務1--開始");
    try {
        Thread.sleep(20000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    logger.error("任務1---結束");
}

好了 大體就是以上的幾點,基本也就知足中小企業遇到的調度問題。固然也可能有描述不許確或者不全面的地方,歡迎指正,哈哈。

相關文章
相關標籤/搜索