zoukankan      html  css  js  c++  java
  • 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张表功能说明:

  • 相关阅读:
    关于loose.dtd和xhtml1transitional.dtd等文档类型定义模型中CSS失效的解决办法。
    JSON扫盲帖+JSON类教程
    jQuery中Ajax事件
    JQuery绑定事件 时如何传递参数
    xml include 另外一个xml文件
    ubuntu 两张网卡时网络设置
    Letcode 题:pow(x,n)
    Java编程语言中sleep()和yield()的区别
    JProfiler与eclipse集成
    zz 字符串相关
  • 原文地址:https://www.cnblogs.com/itlihao/p/14293681.html
Copyright © 2011-2022 走看看