`

Java定时任务调度:用ExecutorService取代Timer

阅读更多
《Java并发编程实战》一书提到的用ExecutorService取代Java Timer有几个理由,我认为其中最重要的理由是:
如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer线程并不捕获异常,所以 TimerTask抛出的未检查的异常会终止timer线程。这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。

stackoverflow上也有关于此问题的讨论:
http://stackoverflow.com/questions/409932/java-timer-vs-executorservice

Timer的问题:
package com.ljn.timer;

import java.util.Date;
import java.util.Timer;

/**
 * @author lijinnan
 * @date:2013-11-25 下午3:27:43  
 */
public class TimerException {

    public static void main(String[] args) {
        System.out.println("start:" + new Date());
        Timer timer = new Timer();
        int delay = 1000;
        int period = 2000;
        timer.schedule(new OKTask(), delay * 2, period);    //"OKTask" does not get chance to execute
        timer.schedule(new ErrorTask(), delay, period);  //exception in "ErrorTask" will terminate the Timer
    }
    
    /*输出:
start:Mon Nov 25 17:49:53 CST 2013
ErrorTask is executing...
error:Mon Nov 25 17:49:55 CST 2013
Exception in thread "Timer-0" java.lang.RuntimeException: something wrong
    at com.ljn.timer.ErrorTask.run(ErrorTask.java:14)
     */

 }



用ExecutorService则正常:
package com.ljn.timer;

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author lijinnan
 * @date:2013-11-25 下午3:35:39  
 */
public class ScheduledExecutorServiceTest {

    public static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);  

    public static void main(String[] args){
        System.out.println("start:" + new Date());
        ErrorTask errorTask = new ErrorTask();
        OKTask okTask = new OKTask();
        int delay = 1000;
        int period = 2000;
        scheduledExecutorService.scheduleAtFixedRate(errorTask, delay, period, TimeUnit.MILLISECONDS);   //"ErrorTask" throws Exception and then stopes.
        scheduledExecutorService.scheduleAtFixedRate(okTask, delay * 2, period, TimeUnit.MILLISECONDS);     //"OKTask" is executed periodically, not affected by "ErrorTask"
        
        //scheduledExecutorService.shutdown();
    }

    /*
start:Mon Nov 25 17:54:22 CST 2013
ErrorTask is executing...
error occurs:Mon Nov 25 17:54:24 CST 2013
OKTask is executed:Mon Nov 25 17:54:24 CST 2013
OKTask is executed:Mon Nov 25 17:54:26 CST 2013
OKTask is executed:Mon Nov 25 17:54:28 CST 2013
......
     */

}



另外开发中常常会让任务在每天的指定时间点运行,示例如下:
package com.ljn.timer;

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author lijinnan
 * @date:2013-11-25 下午5:18:55  
 */
public class FixedDatetimeTaskTest {

    public static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);  

    public static void main(String[] args) throws Exception {
        System.out.println("start:" + new Date());
        
        //每天的02:30:00执行任务
        long delay = Helper.calcDelay(2, 30, 0);
        long period = Helper.ONE_DAY;
        scheduledExecutorService.scheduleAtFixedRate(new OKTask(), delay, period, TimeUnit.MILLISECONDS); 
    }

}



文章中用到的其他类:
package com.ljn.timer;

import java.util.Date;
import java.util.TimerTask;

public class ErrorTask extends TimerTask {

     @Override
     public void run() {
         try {
             System.out.println("ErrorTask is executing...");
             Thread.sleep(1000);
             System.out.println("error occurs:" + new Date());
             throw new RuntimeException("something wrong");
         } catch (InterruptedException e) {
         }
     }
     
 }


package com.ljn.timer;

import java.util.Date;
import java.util.TimerTask;

 
public  class OKTask extends TimerTask {
     
     @Override
     public void run() {
         System.out.println("OKTask is executed:" + new Date());
     }
}


package com.ljn.timer;

import org.joda.time.DateTime;

/**
 * @author lijinnan
 * @date:2013-11-25 下午5:17:40  
 */
public class Helper {

    private Helper() {}
    
    public static final long ONE_DAY = 60 * 60 * 24;
    
    public static long calcDelay(int hour, int minute, int second) {
        if (!(0 <= hour && hour <=23 && 0 <= minute && minute <=59 && 0 <=second && second <= 59)) {
            throw new IllegalArgumentException();
        }
        return calcDelay(fixed(hour, minute, second));
    }
    
    private static long calcDelay(DateTime targetDatetimeOfToday) {
        long delay = 0;
        DateTime now = new DateTime();
        
        //时间点已过,只好延时到明天的这个时间点再执行
        if (now.isAfter(targetDatetimeOfToday)) {
            delay = now.plusDays(1).getMillis() - now.getMillis();
            
        //时间点未到
        } else {
            delay = targetDatetimeOfToday.getMillis() - now.getMillis();
        }
        
        return delay;
    }
    
    /**
     * 返回这样一个DateTime对象:
     * 1.日期为今天
     * 2.时分秒为参数指定的值
     * @param hour 0-23
     * @param minute 0-59
     * @param second 0-59
     * @return
     */
    private static DateTime fixed(int hour, int minute, int second) {
        
        return new DateTime()
                    .withHourOfDay(hour).withMinuteOfHour(minute).withSecondOfMinute(second);
    }

}

0
0
分享到:
评论

相关推荐

    Java语言定时调度任务之实现.zip

    1. **Java内置定时器:java.util.Timer** Java标准库提供了一个`Timer`类,它允许程序员安排在未来某个时间执行一个任务,或者定期重复执行任务。`TimerTask`是与`Timer`配合使用的具体任务类。虽然简单易用,但`...

    Java定时任务

    Java标准库提供了一个基础框架——java.util.Timer和TimerTask类,可以实现简单的定时任务。然而,由于它们在多线程处理上的局限性,实际生产环境中往往更倾向于使用更强大的第三方库,如Quartz和Spring Framework的...

    Java调度原理及使用

    为了解决`Timer`的问题,Java 5引入了`ScheduledExecutorService`,它是`ExecutorService`的一个扩展,支持定时和周期性的任务调度。`ScheduledExecutorService`基于线程池模型,每个任务都由单独的线程执行,因此...

    任务调度,任务调度,任务调度

    而在应用程序中,如Java的ExecutorService或者Python的ThreadPoolExecutor,我们可以自定义任务池来实现特定的调度需求。 任务池是一种管理线程或工作线程的机制,它允许预先创建一组线程,并将任务提交到这个池中...

    JAVA将一个数据中数据定时自动复制(抽取)到另一个数据库

    2. **定时任务**:Java提供了多种方式实现定时任务,如`java.util.Timer`和`TimerTask`,但更推荐使用`java.time`包中的`ScheduledExecutorService`,因为它提供了更精确的定时控制和更好的并发性能。我们可以通过`...

    java并发编程:Executor、Executors、ExecutorService.docx

    Java并发编程中的Executor、Executors和ExecutorService是Java并发编程框架的重要组成部分,它们为开发者提供了高效管理和控制线程执行的工具。以下是对这些概念的详细解释: 1. Executor: Executor是一个接口,它...

    taskTimer 线程 任务

    2. **定时调度任务**:然后,你可以创建一个`Timer`实例,并调用其`schedule()`方法来设定任务的执行时间。例如,如果你想让任务在5秒后执行一次,可以这样写: ```java Timer timer = new Timer(); timer.schedule...

    几种定时任务(Timer、TimerTask、ScheduledFuture)的退出—结合真实案例【JAVA并发】.docx

    Timer类是一个用于调度定时任务的工具,它使用单个后台线程来执行任务。TimerTask是Timer类所调度的任务的抽象类,我们需要创建其子类并重写run()方法来实现具体的业务逻辑。例如,在文件生成监控的场景下,我们可以...

    java多线程并发executorservice(任务调度)类

    在提供的代码示例中,`BeeperControl` 类展示了如何使用 `ScheduledExecutorService` 来实现定时任务调度。首先,它创建了一个单线程的 `ScheduledExecutorService` 实例,通过 `Executors.newScheduledThreadPool(1...

    java 实现调度器

    在Java编程语言中,实现调度器是一个常见的任务,它涉及到定时执行特定的代码段或任务。这通常是通过Java中的`java.util.Timer`类或者`java.util.concurrent.ScheduledExecutorService`来实现的。这两个工具提供了...

    多线程定时任务邮件服务

    在Java中,可以使用`java.util.Timer`和`TimerTask`类来实现简单的定时任务,但它们不适合大量并发或精确调度。更推荐使用`ScheduledExecutorService`,它提供了更灵活的定时和周期性任务调度功能,包括延迟执行和...

    java定时spring定时源码包含定时和spring必须包直接导入可运行无需连接数据库

    `Timer`类适用于简单的定时任务,但其处理线程调度的方式可能导致内存泄漏。相比之下,`ScheduledExecutorService`更推荐使用,它是`ExecutorService`的子接口,提供了延迟执行和定期执行任务的功能,更符合现代并发...

    java版的定时关机小程序 使用java 语言实现

    在Java中,我们可以利用`java.util.Timer`类或`java.util.concurrent.ScheduledExecutorService`来创建定时任务。`Timer`类适用于简单的定时任务,而`ScheduledExecutorService`则提供了更高级的功能,如周期性执行...

    Java定时器Timer简述共8页.pdf.zip

    Java定时器(Timer)是Java语言提供的一种用于执行定时任务的工具类,它位于java.util包下。在Java编程中,我们有时需要在特定的时间间隔内执行某些操作,例如每隔一段时间更新数据、发送通知或者执行定期维护等。这...

    spring定时任务关键jar包(齐全)

    可以使用`ThreadPoolTaskScheduler`来创建一个基于线程池的调度器,或者使用`ConcurrentTaskScheduler`来利用`java.util.concurrent`API进行调度。 3. **@Scheduled注解**: Spring为定时任务提供了`@Scheduled`注解...

    在spring boot中使用java线程池ExecutorService的讲解

    在 Spring Boot 中使用 Java 线程池 ExecutorService 的讲解 Spring Boot 作为一个流行的 Java 框架,提供了许多便捷的功能来帮助开发者快速构建应用程序。其中之一就是使用 Java 线程池 ExecutorService 来管理...

    【Java毕业设计】挖坑,毕业后做了几年的任务调度,想聊聊分布式任务调度系统的设计与实现,打算先用 Java 写一版.zip

    在Java中,可以使用队列(如RabbitMQ或Kafka)来暂存待处理的任务,或者直接调用调度服务接口添加任务。 2. **任务分发**:任务分发器接收任务并决定哪个节点最适合执行任务。这通常基于节点的负载、任务类型、...

    电梯调度算法(java实现)

    同时,利用Java的并发库(如ExecutorService和Callable)可以实现多线程模拟,使电梯调度更具现实感。 总的来说,电梯调度算法的Java实现不仅能够帮助我们理解操作系统中的进程调度原理,还提供了实际编程应用的...

    定时的爱-完成定时任务的加载和发送

    "定时的爱-完成定时任务的加载和发送"这个标题暗示了我们正在探讨的是如何在Java环境中实现定时任务的加载和调度,可能涉及文件传输、消息发送等场景。下面将详细讲解Java中实现定时任务的常见方法和技术。 1. **...

Global site tag (gtag.js) - Google Analytics