java实现定时任务解决方案

在线corn表达式

1. 总结常见的实现定时任务的几种方法

  • thread实现 【原理:通过创建一个线程,让他在while循环里面一直运行,用sleep() 方法让其休眠从而达到定时任务的效果。】
  • Timer类
  • ScheduledExcecutorService类
  • 使用spring的 spring-task 实现
  • Quartz

以下演示几种实现方式:每隔一秒打印一次hello world

1.1 thread实现

public static void main(String[] args) {
	final long timeInterval = 1000;
	
	Runnable runnable = new Runnable() {
		@Override
		public void run() {
			while (true) {
				System.out.println("hello world");
				try {
					Thread.sleep(timeInterval);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	};
	
	Thread thread = new Thread(runnable);
	thread.start();
}

1.2 Timer类实现

Timer是jdk中自带的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。但封装任务的类是TimerTask类(实际该类是一个抽象类,执行任务的代码要放在该类的子类中)。

TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。

构造方法:

成员方法:

public static void main(String[] args) {
	TimerTask task = new TimerTask() {
		@Override
		public void run() {
			System.out.println("Hello!Word!");
		}
	};
	
	Timer timer = new Timer();
	long delay = 0;
	long intevalPeriod = 1 * 1000;
	timer.scheduleAtFixedRate(task, delay, intevalPeriod);
}

schedule 与 scheduleAtFixedRate区别:

schedule会保证任务的间隔是按照定义的period参数严格执行的,如果某一次调度时间比较长,那么后面的时间会顺延,保证调度间隔都是period。
scheduleAtFixedRate是严格按照调度时间来的,如果某次调度时间太长了,那么会通过缩短间隔的方式保证下一次调度在预定时间执行。

线程安全, 但只会单线程执行, 如果执行时间过长, 就错过下次任务了, 抛出异常时, timerWork会终止
启动和取消任务是可以控制的

1.3 ScheduledExcecutorService类实现

ScheduledExecutorService是JDK1.5以后java.util.concurrent中的一个接口, 用于实现定时任务。

public static void main(String[] args) {
	Runnable r1 = new Runnable() {
		public void run() {
			System.out.println("Hello Word");
		}
	};
	ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
	// 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
	service.scheduleAtFixedRate(r1, 3, 1, TimeUnit.SECONDS);// 3秒后开始执行
}

他是通过线程池的方式执行任务,可以多线程执行。
启动和取消任务是可以控制的
可以设定第一次的延迟时间

1.4 使用spring提供的 spring-task 实现

a) 只需要导入web的starter依赖
b) 在启动类上添加 @EnableScheduling 注解
c) 用 @Scheduled 注解开启一个定时任务。

@Component
public class SchedulerTask {
	private int count = 0;
	
	/**
	 * @Author Smith
	 * @Description 设置每1秒执行一次
	 * @Date 14:23 2019/1/24
	 * @Param
	 * @return void
	 **/
	@Scheduled(cron = "*/1 * * * * ?") // 基于cron表达式实现
	private void process(){
		System.out.println("hello world " + (count++));
	}
}

@Scheduled 该注解的常用参数说明【不基于cron表达式实现的时候】:
fixedRate 表示任务执行之间的时间间隔,具体是指两次任务的开始时间间隔,即第二次任务开始时,第一次任务可能还没结束。
fixedDelay 表示任务执行之间的时间间隔,具体是指本次任务结束到下次任务开始之间的时间间隔。
initialDelay 表示首次任务启动的延迟时间。
所有时间的单位都是毫秒。

1.5 Quartz

参考
源码
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。

Quartz默认是多线程异步执行,单个任务时,在上一个调度未完成时,下一个调度时间到时,会另起一个线程开始新的调度。
Quartz支持集群定时任务

Quartz与Spring Task区别

  • Quartz默认多线程异步执行,Task默认单线程同步执行。
  • Quartz单个任务时,在上一个调度未完成时,下一个调度时间到时,会另起一个线程开始新的调度。Task单个任务时,当前次的调度完成后,再执行下一次任务调度。
  • Quartz多个任务时,任务之间没有直接影响,多任务执行的快慢取决于CPU的性能。Task多个任务时,一个任务执行完成后才会执行下一个任务。若需要任务能够并发执行,需手动设置线程池
  • Quartz可以采用集群方式,分布式部署到多台机器,分配执行定时任务

两者对比总结:
1、实现,Task注解实现方式,比较简单。Quartz需要手动配置Jobs。
2、任务执行,Task默认单线程串行执行任务,多任务时若某个任务执行时间过长,后续任务会无法及时执行。Quartz采用多线程,无这个问题。
3、调度,Task采用顺序执行,若当前调度占用时间过长,下一个调度无法及时执行;
4、Quartz采用异步,下一个调度时间到达时,会另一个线程执行调度,不会发生阻塞问题,但调度过多时可能导致数据处理异常
5、部署,Quartz可以采用集群方式,分布式部署到多台机器,分配执行定时任务


Quartz 核心概念:
a) Job 表示一个工作,要执行的具体内容。此接口中只有一个方法。Task多个任务时,一个任务执行完成后才会执行下一个任务。若需要任务能够并发执行,需手动设置线程池。

void execute(JobExecutionContext context) 

b) JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
c) Trigger 代表一个调度参数的配置,什么时候去调。
d) Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。

Spring Boot整合Quartz:

  1. 导入Quartz依赖
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

  1. 编写任务类
public class Task implements Job {

        // 任务类不能直接注入Bean,若想注入Bean需要配置第4步
	@Autowired 
	private TestService service;

	private void before(){
		System.out.println("定时任务开始");
	}

	@Override
	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		service.testDemo();
		System.out.println("hello quartz");
	}
	
	private void afer(){
		System.out.println("定时任务结束");
	}
}
★ 任务类不能直接注入Bean,若想注入Bean需要配置第4步 ★

  1. 编写Quartz配置
@Configuration
public class QuartzConfig {
	
	@Bean
	public JobDetailFactoryBean jobDetailFactoryBean() {
		JobDetailFactoryBean factory = new JobDetailFactoryBean();
		//关联我们自己的Job类
		factory.setJobClass(Task.class);
		return factory;
	}
	
	@Bean
	public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
		CronTriggerFactoryBean factory = new CronTriggerFactoryBean();
		factory.setJobDetail(jobDetailFactoryBean.getObject());
		//设置触发时间
		factory.setCronExpression("0/2 * * * * ?");
		return factory;
	}
	
	@Bean
	public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyAdaptableJobFactory jobFactory) {
		SchedulerFactoryBean factory = new SchedulerFactoryBean();
		//关联trigger
		factory.setTriggers(cronTriggerFactoryBean.getObject());
		factory.setJobFactory(jobFactory);
		return factory;
	}
}

  1. 编写配置【用于任务类能注入我们的bean】
@Component
public class MyAdaptableJobFactory extends AdaptableJobFactory {

    // 可以将一个对象添加到SpringIOC 容器中,并且完成该对象注入
    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    /**
     * 该方法需要将实例化的任务对象手动的添加到springIOC 容器中并且完成对象的注入
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object obj = super.createJobInstance(bundle);
        //将obj 对象添加Spring IOC 容器中,并完成注入
        this.autowireCapableBeanFactory.autowireBean(obj);
        return obj;
    }
}

2 Quartz[群集环境]

使用quartz实现定时任务[单机版],若是部署多台机器,那么到了时间点,多台服务器便会同时均开始执行定时任务。
Quartz是能适用于分布式集群环境的,在同一时间只会有一台机器执行定时任务。

Quartz 中集群如何工作:
一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。意思是你必须对每个节点分别启动或停止。不像许多应用服务器的集群,独立的 Quartz 节点并不与另一其的节点或是管理节点通信。Quartz 应用是通过数据库表来感知到另一应用的。离开了db将无法感知

2.1 导入依赖

<!-- spring boot2.x + quartz -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

2.2 数据库建表

到官网下载
下载之后解压,进入如下目录,创建数据库表:






11张表功能说明:

原文地址:https://www.cnblogs.com/itlihao/p/14293681.html