基於spring註解的定時任務-並行執行

一、定時任務簡述:指定觸發規則後,按照必定的頻率自動往復執行。默認只有一個單例化的線程池(始終只有一個線程)java

         去處理定時任務;只有一個線程時,多個任務須要並行(同時)執行時會產生時間差【每一個任務從執行開始spring

         到結束須要的時間不一樣,單線程狀況下,只能等前一個任務結束才能開始執行下一個任務】,致使實際異步

        上每一個任務不是按照指定的指定的頻率執行。能夠經過配置線程池來解決。spa

  1.一、非異步定時任務:從任務開始到結束都是同一個線程(即便執行過程當中有線程阻塞)線程

    【當前任務執行完畢後纔會根據任務執行條件再次觸發code

      異步定時任務(方法上有@Asycn註解): 從任務開始,假設進入阻塞狀態,任務結束時和任務開始時不必定是component

      同一個線程處理的【當前任務沒有執行完畢,但任務執行條件觸發則直接建立新線程執行任務orm

二、相關依賴 xml

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.12.RELEASE </version> 
</dependency>

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

三、 簡要的配置說明blog

  3.1添加命名空間 

xmlns:task="http://www.springframework.org/schema/task
http://www.springframework.org/schema/task 
http://www.springframework.org/schema/task/spring-task-4.1.xsd

  3.2 spring配置文件【該文件須要spring讀取

<!-- 定時任務,配置須要掃描的包 -->
<context:component-scan base-package="com.demo.quartz" />
<!-- 用於激活那些已經在spring容器裏註冊過的bean(不管是經過xml的方式仍是經過package scanning的方式)上面的註解 可不配置 --> <context:annotation-config/>
<!-- 配置處理定時任務的線程池 --> <task:scheduler id="scheduler" pool-size="10" />
<!-- 配置處理 異步定時任務的 線程池 -->
<!--
  pool-size:線程池大小 keep-alive:線程最大空閒時間
  queue-capacity:隊列大小(無線程可用時,其他任務放置隊列中,隊列放滿後其餘任務只能等待)
  rejection-policy:隊列任務數達到最大時,處理其餘任務的策略
--> <task:executor id="taskExecutor" pool-size="10" keep-alive="2000" rejection-policy="DISCARD_OLDEST"
  queue-capacity="10" />
<!-- 配置spring定時開關--> <task:annotation-driven executor="taskExecutor" scheduler="scheduler" />

  3.三、@Scheduled註解中屬性設置 

    cron:執行任務觸發頻率規則:cron表達式詳情查看另外一博主介紹:http://biaoming.iteye.com/blog/39532   

@Scheduled(fixedRate=3000) //上一次任務  開始執行後3秒 再次執行
@Scheduled(fixedDelay=3000) //上一次    任務執行結束後 3秒,再次執行
@Scheduled(initialDelay=1000,fixedDelay=3000) //第一次延時1秒執行,之後每次任務執行完後3秒再次執行  

四、簡單demo

package com.demo.quartz;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@EnableScheduling //開啓spring定時任務
@Lazy(false)   //默認是true爲懶下載,此處設置false
public class TestQuartz {
    @Scheduled(cron="0/1 * * * * ?")
    public void test1() {
        //AsyncConfigurer
//        ThreadPoolTaskScheduler  tpt  = new ThreadPoolTaskScheduler();
//        System.err.println(tpt.getPoolSize());
        //org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 
        //SchedulingConfigurer
        try {
            //  源碼相關的類
            //ScheduledExecutorService
            //ScheduledTaskRegistrar 
            //TaskScheduler
            //ThreadPoolTaskScheduler
            //ThreadPoolTaskExecutor
            //org.springframework.scheduling.config.ScheduledTaskRegistrar;
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
        System.out.println(Thread.currentThread().getName()+"----------1-----------"+sdf.format(new Date()));
    }
    
    @Scheduled(cron="0/1 * * * * ?")
    public void test2() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");  
        System.out.println(Thread.currentThread().getName()+"----------3-----------"+sdf.format(new Date()));
    }
    @Scheduled(cron="0/1 * * * * ?")
    public void test3() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
        System.out.println(Thread.currentThread().getName()+"----------4-----------"+sdf.format(new Date()));
    }
    
    @Async
    @Scheduled(cron="0/1 * * * * ?")
    public void test4() {
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
        try {
            System.err.println(Thread.currentThread().getName()+"----------2-----------查看線程名稱-阻塞前"+sdf.format(new Date()));
            Thread.sleep(3000);
            System.err.println(Thread.currentThread().getName()+"----------2-----------查看線程名稱-阻塞後"+sdf.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"----------2-----------"+sdf.format(new Date()));
    }
    
    @Async
    @Scheduled(cron="0/1 * * * * ?")
    public void test5() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
        System.out.println(Thread.currentThread().getName()+"----------5-----------"+sdf.format(new Date()));
    }
    @Async
    @Scheduled(cron="0/1 * * * * ?")
    public void test6() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
        System.out.println(Thread.currentThread().getName()+"----------6-----------"+sdf.format(new Date()));
    }
}

五、效果圖

  --------------該數字(表示的任務編號)-----------------------

六、定時任務執行流程源碼解析

  https://unmi.cc/spring-schedule-runner-threads/ 

相關文章
相關標籤/搜索