zoukankan      html  css  js  c++  java
  • Java线程和多线程(十)——TimerTask

    Java中的java.util.Timer是一个工具类,可以用于调度一个线程在将来的某一个时刻执行特定的任务。Java Timer类可以将一个任务定时执行一次,或者是以后以每隔一定的时间间隔来触发一次。

    Java TimerTask

    java.util.TimerTask是一个抽象类,也同时实现了Runnable接口的。我们可以继承这个类来创建我们自己的TimerTask之后由Timer来调度。

    Java Timer举例

    Java Timer类是线程安全的,多个线程可以共享一个Timer对象而不需要额外的同步操作。Timer类会使用java.util.TaskQueue来将Task以一定的时间间隔加入到队列之中,而且,在任何时候仅仅能有一个线程在运行TimerTask。举例来说,开发者创建了一个Timer每隔10秒来执行一次,但是单线程的执行需要使用20秒,那么Timer对象会持续将任务添加到队列中,只要线程的执行完成了,它会通知队列中另一个线程来立刻执行。

    Java Timer类通过对象的waitnotify方法来调度任务。

    参见如下代码:

    package com.sapphire.threads;
    
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class MyTimerTask extends TimerTask {
    
        @Override
        public void run() {
            System.out.println("Timer task started at:"+new Date());
            completeTask();
            System.out.println("Timer task finished at:"+new Date());
        }
    
        private void completeTask() {
            try {
                //assuming it takes 20 secs to complete the task
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String args[]){
            TimerTask timerTask = new MyTimerTask();
            //running timer task as daemon thread
            Timer timer = new Timer(true);
            timer.scheduleAtFixedRate(timerTask, 0, 10*1000);
            System.out.println("TimerTask started");
            //cancel after sometime
            try {
                Thread.sleep(120000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            timer.cancel();
            System.out.println("TimerTask cancelled");
            try {
                Thread.sleep(30000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    需要注意的是,上面的一个线程的执行会花掉20秒,但是Java的Timer对象调度的执行间隔是10秒执行一次,所以输出如下:

    TimerTask started
    Timer task started at:Fri Oct 14 12:59:27 CST 2016
    Timer task finished at:Fri Oct 14 12:59:47 CST 2016
    Timer task started at:Fri Oct 14 12:59:47 CST 2016
    Timer task finished at:Fri Oct 14 13:00:07 CST 2016
    Timer task started at:Fri Oct 14 13:00:07 CST 2016
    Timer task finished at:Fri Oct 14 13:00:27 CST 2016
    Timer task started at:Fri Oct 14 13:00:27 CST 2016
    Timer task finished at:Fri Oct 14 13:00:47 CST 2016
    Timer task started at:Fri Oct 14 13:00:47 CST 2016
    Timer task finished at:Fri Oct 14 13:01:07 CST 2016
    Timer task started at:Fri Oct 14 13:01:07 CST 2016
    TimerTask cancelled
    Timer task finished at:Fri Oct 14 13:01:27 CST 2016

    输出也确认了一点,就是如果一个任务已经开始执行了,那么Timer会等待它的完成,而一旦完成,Timer会立刻开始执行队列中的下一个任务。

    Java的对象可以以守护线程的方式来调度相关的任务。Timer的cancel()方法是用来结束Timer并抛弃其他的调度任务的。然而,这个方法不会影响现在正在执行的任务,而是让其继续运行下去。如果我们将Timer的运行配置为守护线程,那么无论我们是否调用cancel()方法,一旦用户线程完成执行,Timer都会立刻结束掉。

    Timer类中包含多个schedule()方法,可以调度任务在指定时间执行一次,或者在一些延迟后来执行。Timer类中也包含了一些scheduleAtFixedRate()方法来以指定的时间间隔来运行一些任务。

    注意:当使用Timer来进行任务调度的时候,开发者需要确认无时间间隔一定要大于线程的执行时间。否则,任务的队列会变得越来越长而实际的任务也会总是在执行。

    前面的描述也相当于隐含着提到了Timer的可能的错误行为,那就是Timer执行任务的方式。Timer的实现是内部包含一个队列,和一个线程,然后来定时将任务添加到执行队列之中的。

    public class Timer {
        private final TaskQueue queue = new TaskQueue();
        private final TimerThread thread = new TimerThread(queue);
    }

    这样就可能出现问题,如果将2个TimerTask加入到Timer中进行执行,如果其中一个Timer执行的比较忙,而另一个需要执行的又比较快,可能就会出现问题。举例来说,两个任务,一个每隔300秒执行一次,一个每隔5秒执行一次,如果第一个任务执行了20秒才结束,那么因为上面实现的原因,会将第二个任务阻塞20秒,而一口气执行四次。所以开发者在使用Timer来进行任务调度的时候,需要考虑性能以及可能出现的错误行为。

  • 相关阅读:
    更新部分字段 NHibernate
    无法显示 XML 页。 使用 XSL 样式表无法查看 XML 输入。请更正错误然后单击 刷新按钮,或以后重试的解决办法
    初识使用Apache MINA 开发高性能网络应用程序
    生产者消费者问题理解与Java实现
    国内HTML5前段开发框架汇总
    mongodb的sharding架构搭建
    spring配置声明式事务
    如何设计页面固定广告的效果
    结合实际问题浅谈如何使用蒙特卡罗算法模拟投资分析
    多线程实现资源共享的问题学习与总结
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461518.html
Copyright © 2011-2022 走看看