IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    【转】详解java定时任务 (二)

    王 雪松发表于 2014-07-26 01:59:16
    love 0

    三、Timer的缺陷

    3.1、Timer的缺陷

    Timer计时器可以定时(指定时间执行任务)、延迟(延迟5秒执行任务)、周期性地执行任务(每隔个1秒执行任务),但是,Timer存在一些缺陷。首先Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。其次Timer线程是不会捕获异常的,如果TimerTask抛出的了未检查异常则会导致Timer线程终止,同时Timer也不会重新恢复线程的执行,他会错误的认为整个Timer线程都会取消。同时,已经被安排单尚未执行的TimerTask也不会再执行了,新的任务也不能被调度。故如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。

    1、Timer管理时间延迟缺陷

    前面Timer在执行定时任务时只会创建一个线程任务,如果存在多个线程,若其中某个线程因为某种原因而导致线程任务执行时间过长,超过了两个任务的间隔时间,会发生一些缺陷:

    [java]

    public class TimerTest04 {
    private Timer timer;
    public long start;

    public TimerTest04(){
    this.timer = new Timer();
    start = System.currentTimeMillis();
    }

    public void timerOne(){
    timer.schedule(new TimerTask() {
    public void run() {
    System.out.println("timerOne invoked ,the time:" +
    (System.currentTimeMillis() – start));
    try {
    Thread.sleep(4000); //线程休眠3000
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }, 1000);
    }

    public void timerTwo(){
    timer.schedule(new TimerTask() {
    public void run() {
    System.out.println("timerOne invoked ,the time:" +
    (System.currentTimeMillis() – start));
    }
    }, 3000);
    }

    public static void main(String[] args) throws Exception {
    TimerTest04 test = new TimerTest04();

    test.timerOne();
    test.timerTwo();
    }
    }

    [/java]

    按照我们正常思路,timerTwo应该是在3s后执行,其结果应该是:
    timerOne invoked ,the time:1001
    timerOne invoked ,the time:3001

    但是事与愿违,timerOne由于sleep(4000),休眠了4S,同时Timer内部是一个线程,导致timeOne所需的时间超过了间隔时间,结果:

    timerOne invoked ,the time:1000

    timerOne invoked ,the time:5000

    2、Timer抛出异常缺陷

    如果TimerTask抛出RuntimeException,Timer会终止所有任务的运行。如下:

    [java]

    public class TimerTest04 {
    private Timer timer;

    public TimerTest04(){
    this.timer = new Timer();
    }

    public void timerOne(){
    timer.schedule(new TimerTask() {
    public void run() {
    throw new RuntimeException();
    }
    }, 1000);
    }

    public void timerTwo(){
    timer.schedule(new TimerTask() {

    public void run() {
    System.out.println("我会不会执行呢??");
    }
    }, 1000);
    }

    public static void main(String[] args) {
    TimerTest04 test = new TimerTest04();
    test.timerOne();
    test.timerTwo();
    }
    }

    [/java]

    运行结果:timerOne抛出异常,导致timerTwo任务终止。

    Exception in thread “Timer-0″ java.lang.RuntimeException
    at com.chenssy.timer.TimerTest04$1.run(TimerTest04.java:25)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)

    对于Timer的缺陷,我们可以考虑 ScheduledThreadPoolExecutor 来替代。Timer是基于绝对时间的,对系统时间比较敏感,而ScheduledThreadPoolExecutor 则是基于相对时间;Timer是内部是单一线程,而ScheduledThreadPoolExecutor内部是个线程池,所以可以支持多个任务并发执行。

    3.2、用ScheduledExecutorService替代Timer

    1、解决问题一:

    [java]

    public class ScheduledExecutorTest {
    private ScheduledExecutorService scheduExec;

    public long start;

    ScheduledExecutorTest(){
    this.scheduExec = Executors.newScheduledThreadPool(2);
    this.start = System.currentTimeMillis();
    }

    public void timerOne(){
    scheduExec.schedule(new Runnable() {
    public void run() {
    System.out.println("timerOne,the time:" +
    (System.currentTimeMillis() – start));
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    },1000,TimeUnit.MILLISECONDS);
    }

    public void timerTwo(){
    scheduExec.schedule(new Runnable() {
    public void run() {
    System.out.println("timerTwo,the time:" +
    (System.currentTimeMillis() – start));
    }
    },2000,TimeUnit.MILLISECONDS);
    }

    public static void main(String[] args) {
    ScheduledExecutorTest test = new ScheduledExecutorTest();
    test.timerOne();
    test.timerTwo();
    }
    }

    [/java]

    运行结果:

    timerOne,the time:1003

    timerTwo,the time:2005

    2、解决问题二

    [java]

    public class ScheduledExecutorTest {
    private ScheduledExecutorService scheduExec;

    public long start;

    ScheduledExecutorTest(){
    this.scheduExec = Executors.newScheduledThreadPool(2);
    this.start = System.currentTimeMillis();
    }

    public void timerOne(){
    scheduExec.schedule(new Runnable() {
    public void run() {
    throw new RuntimeException();
    }
    },1000,TimeUnit.MILLISECONDS);
    }

    public void timerTwo(){
    scheduExec.scheduleAtFixedRate(new Runnable() {
    public void run() {
    System.out.println("timerTwo invoked …..");
    }
    },2000,500,TimeUnit.MILLISECONDS);
    }

    public static void main(String[] args) {
    ScheduledExecutorTest test = new ScheduledExecutorTest();
    test.timerOne();
    test.timerTwo();
    }
    }

    [/java]

    运行结果:

    timerTwo invoked …..
    timerTwo invoked …..
    timerTwo invoked …..
    timerTwo invoked …..
    timerTwo invoked …..
    timerTwo invoked …..
    timerTwo invoked …..
    timerTwo invoked …..
    timerTwo invoked …..
    ……………………



沪ICP备19023445号-2号
友情链接