Java 定时任务的几种实现方式

介绍三种实现方式:

JDK 自带的定时器实现

  • Timer类 
    这个类允许你调度一个java.util.TimerTask任务。主要有以下几个方法:
 voidschedule(TimerTask task, Date time)
          安排在指定的时间执行指定的任务。
 voidschedule(TimerTask task, Date firstTime, long period)
          安排指定的任务在指定的时间开始进行重复的固定延迟执行
 voidschedule(TimerTask task, long delay)
          安排在指定延迟后执行指定的任务。
 voidschedule(TimerTask task, long delay, long period)
          安排指定的任务从指定的延迟后开始进行重复的固定延迟执行
 voidscheduleAtFixedRate(TimerTask task, Date firstTime, long period)
          安排指定的任务在指定的时间开始进行重复的固定速率执行
 voidscheduleAtFixedRate(TimerTask task, long delay, long period)
          安排指定的任务在指定的延迟后开始进行重复的固定速率执行

ScheduledExecutorService 接口实现类 

java.util.concurrent.ScheduledExecutorService
<V> ScheduledFuture<V>
schedule(Callable<V> callable, long delay, TimeUnit unit)
          创建并执行在给定延迟后启用的 ScheduledFuture。
 ScheduledFuture<?>schedule(Runnable command, long delay, TimeUnit unit)
          创建并执行在给定延迟后启用的一次性操作。
 ScheduledFuture<?>scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
          创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。
 ScheduledFuture<?>scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
          创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。

默认实现为ScheduledThreadPoolExecutor 继承了ThreadPoolExecutor 的线程池特性,配合future特性,比Timer更强大。

 

方法摘要
protected
<V> RunnableScheduledFuture<V>
decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task)
          修改或替换用于执行 callable 的任务。
protected
<V> RunnableScheduledFuture<V>
decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)
          修改或替换用于执行 runnable 的任务。
 voidexecute(Runnable command)
          使用所要求的零延迟执行命令。
 booleangetContinueExistingPeriodicTasksAfterShutdownPolicy()
          获取有关在此执行程序已 shutdown 的情况下、是否继续执行现有定期任务的策略。
 booleangetExecuteExistingDelayedTasksAfterShutdownPolicy()
          获取有关在此执行程序已 shutdown 的情况下是否继续执行现有延迟任务的策略。
 BlockingQueue<Runnable>getQueue()
          返回此执行程序使用的任务队列。
 booleanremove(Runnable task)
          从执行程序的内部队列中移除此任务(如果存在),从而如果尚未开始,则其不再运行。
<V> ScheduledFuture<V>
schedule(Callable<V> callable, long delay, TimeUnit unit)
          创建并执行在给定延迟后启用的 ScheduledFuture。
 ScheduledFuture<?>schedule(Runnable command, long delay, TimeUnit unit)
          创建并执行在给定延迟后启用的一次性操作。
 ScheduledFuture<?>scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
          创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。
 ScheduledFuture<?>scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
          创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。
 voidsetContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value)
          设置有关在此执行程序已 shutdown 的情况下是否继续执行现有定期任务的策略。
 voidsetExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value)
          设置有关在此执行程序已 shutdown 的情况下是否继续执行现有延迟任务的策略。
 voidshutdown()
          在以前已提交任务的执行中发起一个有序的关闭,但是不接受新任务。
 List<Runnable>shutdownNow()
          尝试停止所有正在执行的任务、暂停等待任务的处理,并返回等待执行的任务列表。
<T> Future<T>
submit(Callable<T> task)
          提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
 Future<?>submit(Runnable task)
          提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
<T> Future<T>
submit(Runnable task, T result)
          提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。

Quartz 定时器实现

Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。可以动态的添加删除定时任务,另外很好的支撑集群调度。简单地创建一个org.quarz.Job接口的Java类,Job接口包含唯一的方法:

public void execute(JobExecutionContext context) throws JobExecutionException;
  • 在Job接口实现类里面,添加需要的逻辑到execute()方法中。配置好Job实现类并设定好调度时间表(Trigger),Quartz就会自动在设定的时间调度作业执行execute()。

整合了Quartz的应用程序可以重用不同事件的作业,还可以为一个事件组合多个作业。Quartz通过属性文件来配置JDBC事务的数据源、全局作业、触发器侦听器、插件、线程池等等。(quartz.properties)

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
  1. 创建Job类
public class TestJob implements Job{
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        println(Thread.currentThread().getName() + " test job begin " + DateUtil.getCurrentTimeStr());
    }
}

2.调度任务

public static void main(String[] args) throws InterruptedException, SchedulerException {

        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        // 开始
        scheduler.start();
        // job 唯一标识 test.test-1
        JobKey jobKey = new JobKey("test" , "test-1");
        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("test" , "test")
                // 延迟一秒执行
                .startAt(new Date(System.currentTimeMillis() + 1000))
                // 每隔一秒执行 并一直重复
        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever())
                .build();
        scheduler.scheduleJob(jobDetail , trigger);

        Thread.sleep(5000);
        // 删除job
        scheduler.deleteJob(jobKey);
    }

out :
DefaultQuartzScheduler_Worker-1test job begin 2017-06-03 14:30:33
DefaultQuartzScheduler_Worker-2test job begin 2017-06-03 14:30:34
DefaultQuartzScheduler_Worker-3test job begin 2017-06-03 14:30:35
DefaultQuartzScheduler_Worker-4test job begin 2017-06-03 14:30:36
DefaultQuartzScheduler_Worker-5test job begin 2017-06-03 14:30:37

Quartz 主要包含以下几个部分

Job:是一个接口,只有一个方法void execute(JobExecutionContext

context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中;

JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。

Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等;

Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。

Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler#

getContext()获取对应的SchedulerContext实例;

ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。

关于简单使用,可以参考quartz的example,下面链接是一些入门帮助。

Quartz定时任务学习(一)简单任务 
Quartz定时任务学习(二)web应用 
Quartz定时任务学习(三)属性文件和jar

深入学习可以阅读官方文档和相关博客阅读 
以下为推荐博客地址 
quartz详解2:quartz由浅入深

Spring 相关的任务调度

  1. Spring 3.0+ 自带的任务调度实现,主要依靠TaskScheduler接口的几个实现类实现。删除和修改任务比较麻烦。 
    主要用法有以下三种: 
    • Spring配置文件实现
    • 注解实现
    • 代码动态添加

配置文件实现

spring-schedule.xml

<task:scheduler id="myScheduler" pool-size="10" />
<task:scheduled-tasks scheduler="myScheduler">
    <task:scheduled ref="job" method="test" cron="0 * * * * ?"/>
</task:scheduled-tasks>

注解实现

spring-schedule.xml
<task:scheduler id="myScheduler" pool-size="10" />
// 启用注解
<task:annotation-driven scheduler="myScheduler"/> 
@Component  
public class Task{  

       @Scheduled(cron="0/5 * *  * * ? ")   //每5秒执行一次       
       public void execute(){     
             DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    
             System.out.println(sdf.format(DateTime.now().toDate())+"*********B任务每5秒执行一次进入测试");      
       }      
}  

代码动态添加

spring-schedule.xml

<bean id = "myScheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
        <property name="poolSize" value="10"/>
        <property name="threadGroupName" value="myScheduler" />
        <property name="threadNamePrefix" value="-1" />
</bean>
<task:annotation-driven scheduler="myScheduler"/> 
@Component
public class Test {

    @Autowired
    private ThreadPoolTaskScheduler myScheduler;

    public void addJob(){

        myScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " run ");
            }
        } , new CronTrigger("0/5 * *  * * ? ")); //每5秒执行一次
    }
}

spring 结合 quartz 实现任务调度 

  • spring 配置文件 spring-quartz.xml
<bean id="quartzsScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
        <property name="triggers">
            <list>
            <ref bean="testTrigger" />
            </list>
        </property>
</bean>

<!-- jobClass需要继承QuartzJobBean  也可以使用 MethodInvokingJobDetailFactoryBean 定义任意类任意方法为Job-->
<bean id="testJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
              <property name="jobClass">
                     <value>com.test.TestJob</value>
              </property>
              <property name="durability" value="true" />
              <!-- requestsRecovery属性必须设置为 true,当Quartz服务被中止后,再次启动或集群中其他机器接手任务时会尝试恢复执行之前未完成的所有任务 -->
              <property name="requestsRecovery" value="true" />
</bean>
<bean id="testTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
              <property name="jobDetail" ref="testJobDetail" />
              <property name="cronExpression" value="0 0 10 * * ?" />
</bean>

动态增加删除

@Component
public class Test {

    @Autowired
    private SchedulerFactoryBean quartzScheduler;

    public void addJob() throws SchedulerException {

        Scheduler scheduler = quartzScheduler.getScheduler();
        JobKey jobKey = new JobKey("test", "test");
        if (scheduler.checkExists(jobKey)) {
            return;
        }
        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("test", "test")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever()).build();
        scheduler.scheduleJob(jobDetail, trigger);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。 Quartz的优势: 1、Quartz是一个任务调度框架(库),它几乎可以集成到任何应用系统中。 2、Quartz是非常灵活的,它让您能够以最“自然”的方式来编写您的项目的代码,实现您所期望的行为 3、Quartz是非常轻量级的,只需要非常少的配置 —— 它实际上可以被跳出框架来使用,如果你的需求是一些相对基本的简单的需求的话。 4、Quartz具有容错机制,并且可以在重启服务的时候持久化(”记忆”)你的定时任务,你的任务也不会丢失。 5、可以通过Quartz,封装成自己的分布式任务调度,实现强大的功能,成为自己的产品。6、有很多的互联网公司也都在使用Quartz。比如美团 Spring是一个很优秀的框架,它无缝的集成了Quartz,简单方便的让企业级应用更好的使用Quartz进行任务的调度。   课程说明:在我们的日常开发中,各种大型系统的开发少不了任务调度,简单的单机任务调度已经满足不了我们的系统需求,复杂的任务会让程序猿头疼, 所以急需一套专门的框架帮助我们去管理定时任务,并且可以在多台机器去执行我们的任务,还要可以管理我们的分布式定时任务。本课程从Quartz框架讲起,由浅到深,从使用到结构分析,再到源码分析,深入解析Quartz、Spring+Quartz,并且会讲解相关原理, 让大家充分的理解这个框架和框架的设计思想。由于互联网的复杂性,为了满足我们特定的需求,需要对Spring+Quartz进行二次开发,整个二次开发过程都会进行讲解。Spring被用在了越来越多的项目中, Quartz也被公认为是比较好用的定时器设置工具,学完这个课程后,不仅仅可以熟练掌握分布式定时任务,还可以深入理解大型框架的设计思想。
### 回答1: 答:Java实现定时任务方式有三种:1.使用java.util.Timer类;2.使用java.util.concurrent.ScheduledThreadPoolExecutor类;3.使用Quartz框架。 ### 回答2: Java实现定时任务有以下几种方式: 1. Timer类:Java提供了Timer类来帮助实现定时任务。通过创建一个Timer实例和一个TimerTask实例,可以设定任务的执行时间和间隔时间,然后使用Timer的schedule()方法来启动任务。 2. ScheduledExecutorService接口:Java提供了ScheduledExecutorService接口来实现定时任务。该接口继承自ExecutorService接口,可以使用ThreadPoolExecutor来实现。通过调用schedule()方法,可以设定任务的执行时间和间隔时间,然后将任务提交给ScheduledExecutorService。 3. cron表达式:在Java中,还可以使用cron表达式来实现定时任务。cron表达式是一种用来设置时间的字符串格式,通过设置不同的字段,可以实现精确到秒的定时任务。可以使用Quartz框架等工具来解析和执行cron表达式。 4. Spring框架的@Scheduled注解:如果在Spring框架中开发应用,可以使用@Scheduled注解来实现定时任务。通过在方法上标记@Scheduled注解,并设置相应的时间表达式,可以让方法在指定的时间间隔内执行。 需要注意的是,以上方式都是基于Java定时任务实现,可以根据具体需求选择最合适的方式实现定时任务。 ### 回答3: 在Java中,我们可以使用以下几种方式实现定时任务。 1. Timer类:Java中的Timer类是一个简单的定时器工具,它可以通过创建Timer对象并调用其schedule()方法来设置定时任务。该方法可以指定一个任务(实现了TimerTask接口的类)和一个延迟时间,然后在延迟时间之后开始执行定时任务。 2. ScheduledExecutorService接口:Java中的ScheduledExecutorService接口是一个在指定的延迟时间之后或者以固定的时间间隔重复执行任务的调度器。可以使用Executors工厂类的newScheduledThreadPool()方法创建ScheduledExecutorService对象,并使用其schedule()方法来设置定时任务。 3. Quartz框架:Quartz是一个功能强大且灵活的开源定时任务调度框架。它提供了许多高级的调度功能,如任务的并发执行、动态调度、集群支持等。使用Quartz框架,我们可以通过配置定时任务的详细信息(如触发器、调度器等),然后让框架来管理和执行定时任务。 4. Spring的Task:Spring框架提供了一个简单的任务调度器,可以通过配置的方式实现定时任务。在Spring的配置文件中,我们可以使用<task:scheduler>和<task:scheduled>标签来定义定时任务的调度器和具体的定时任务方法。 综上所述,Java实现定时任务方式有多种选择。根据需求的复杂性和灵活性的要求,我们可以选择适合的方式实现定时任务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值