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


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

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

         到結束需要的時間不同,單線程情況下,只能等前一個任務結束才能開始執行下一個任務】,導致實際

        上每個任務不是按照指定的指定的頻率執行。可以通過配置線程池來解決。

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

    【當前任務執行完畢后才會根據任務執行條件再次觸發

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

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

2、相關依賴 

<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>

3、 簡要的配置說明

  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.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秒再次執行  

4、簡單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()));
    }
}

5、效果圖

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

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

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM