没有梦想,何必远方

基于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/ 

 

posted @ 2018-03-18 10:41  北极丶光  阅读(6878)  评论(0编辑  收藏  举报