精华内容
下载资源
问答
  • java里面定时器

    2019-03-17 02:03:14
    现在看来,不算一个很好的设计。 Timer timer = new Timer(); timer.schedule(new MyTimerTask(),1000,10); 其中MyTimerTask 是一个实现TimerTask的类,主要是实现run 方法。 Timer中有2个核心类,一个是Timer,...

    Timer

    JDK中的Timer 是一个非常早期的类,在1.2中就引入了。现在看来,不算一个很好的设计。

    Timer timer = new Timer();
    timer.schedule(new MyTimerTask(),1000,10);

    其中MyTimerTask 是一个实现TimerTask的类,主要是实现run 方法。

    Timer中有2个核心类,一个是Timer,一个TimerTask

    前者主要是定义定时任务什么时候执行,后者主要是定义具体定时任务。

    Timer

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

    其中TaskQueue 是使用数组实现的一个简易的堆,另外一个值得注意的属性是 TimerThread

    Timer使用唯一的线程负责轮询并执行任务。Timer的优点在于简单易用,但也因为所有任务都是由同一个线程来调度,因此整个过程是串行执行的,同一时间只能有一个任务在执行,所以在任务量多的情况下不方便使用。

    1.Timer 只能被单线程调度

    2.TimerTask 中出现的异常会影响到Timer 的执行

    由于这两点缺陷,JDK1.5 支持了新的定时器方案 ScheduledExecutorService。

    ScheduledExecutorService

    public static void main(String[] args) {
            ScheduledExecutorService scheduledExecutorService =
                    Executors.newScheduledThreadPool(10);
            scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    System.out.println("schedualed executor service");
                }
            },1, 1, TimeUnit.SECONDS);
        }

    相比Timer,ScheduledExecutorService 解决了同一个定时器调度多个任务的阻塞问题,并且任务异常不会中断 ScheduledExecutorService。

    ScheduledExecutorService 提供了2种常用的周期调度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。

    ScheduleAtFixedRate 基于固定时间间隔进行任务调度,ScheduleWithFixedDelay 取决于每次任务执行的时间长短,是基于不固定时间间隔的任务调度。

    ScheduledExecutorService 底层使用的数据结构为 PriorityQueue。

     

    展开全文
  • java Web定时器

    千次阅读 2012-04-25 17:04:45
    首先介绍java定时器java.util.Timer)有定时执行计划任务的功能,通过设定定时器的间隔时间,会自动在此间隔时间后执行预先安排好的任务(java.util. TimerTask) 如: 每隔一个小时执行任务 timer.schedule(TimerTask...

    这个类最终功能是每天某个时间点(如每晚22点)执行某一功能.

    首先介绍java定时器(java.util.Timer)有定时执行计划任务的功能,通过设定定时器的间隔时间,会自动在此间隔时间后执行预先安排好的任务(java.util. TimerTask)

    如: 每隔一个小时执行任务 timer.schedule(TimerTask, 0, 60 * 60 * 1000);

        schedule方法的第一个参数是需要执行的任务,此类的类型为java.util.TimerTask,第二个参数为执行任务前等待时间,此处0表示不等待,第三个参数为间隔时间,单位为毫秒

    由于我们希望当Web工程启动时,定时器能自动开始计时,这样在整个Web工程的生命期里,就会定时的执行任务,因此启动定时器的类不能是一般的类,此处用Servlet的监听器类来启动定时器,通过在配置文件里配置此监听器, 让其在工程启动时自动加载运行,存活期为整个Web工程生命期.

    要运用Servlet侦听器需要实现javax.servlet.ServletContextListener接口,以下是类设计:



    publicclass TimerListener implements ServletContextListener {

     

         private Timertimer = null;

     

         private SampleTask sampleTask;

     

     

       

        @Override

        publicvoid contextDestroyed(ServletContextEvent event) {

            timer.cancel();

     

            event.getServletContext().log("定时器销毁");

     

     

     

        }

     

        @Override

        publicvoid contextInitialized(ServletContextEvent event) {

            timer = new Timer(true);

     

            sampleTasknewSampleTask(event.getServletContext());

     

            event.getServletContext().log("定时器已启动");

     

            timer.schedule(sampleTask, 0, 60 * 60 * 1000);

     

            event.getServletContext().log ("已经添加任务调度表");

     

        }

     

    }

     

    publicclass SampleTask extends TimerTask {

     

       

        private ServletContext context;

       

        privatestaticbooleanisRunning = false;

         

        privatestaticbooleanflag = true;

         

        privatestaticfinalintC_SCHEDULE_HOUR = 15;

         

        public SampleTask(ServletContextcontext){

     

            this.context = context;

     

        }

       

        @Override

        publicvoid run() {

            Calendar cal = Calendar.getInstance();

             

              if (!isRunning) {

         

                  if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY) && flag) {

                      isRunning = true;

                      context.log("开始执行指定任务");

     

                      //需要执行的代码

                    

                      isRunning = false;

                      flag = false;

                      context.log("指定任务执行结束");

                  }

              } else {

                  context.log("上一次任务执行还未结束");

              }

         

              if(C_SCHEDULE_HOUR != cal.get(Calendar.HOUR_OF_DAY)){

         

                  flag = true;

         

              }

        }

    }
    要使用此监听器需要在web.xml中配置,如下:
    <listener>
      <listener-class>包路径.TimerListener</listener-class>
    </listener>

    这样在web工程启动时,就会自动启动此监听器.

     

     

    JAVA中Timer定时器调度方法

    java timer中的时间调度方法主要有:
    schedule(TimerTask task, Date firstTime, long period)
              Schedules the specified task for repeated fixed-delay execution, beginning at the specified time.

    但是如果此时的firstTime小于(时间落后于)当前时间,那么
    task会立即执行,在调试的时候不方便,因为程序一启动就开始执行了,或许还没有到任务的触发点。

    schedule(TimerTask task, long delay, long period)
              Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay.

    如果采用设置delay时间的方法,则可以进行处理。
    比如:设置执行时间为每天的13:50,如果启动的时候时间已经过了13:35,那么应该在明天的13:35进行执行。此时可以这样处理:

    Calendar cal = Calendar.getInstance();
            cal.set(Calendar.HOUR_OF_DAY, 13);
            cal.set(Calendar.MINUTE, 35);
            //cal.add(Calendar.DAY_OF_MONTH, 1);
            Date date = new Date();
            date = cal.getTime();
           
            Date now = new Date();
            long interval = date.getTime() - now.getTime();
            //should exec in next day
            if (interval < 0) {
                cal.add(Calendar.DAY_OF_MONTH, 1);
                date = cal.getTime();
                interval = date.getTime() - now.getTime();
            }      
            System.out.println("the interval time is: " + interval);
            //the exec time interval is 2 secs.
            timer.schedule(echoTask, interval, 2 * 1000);
    如果delay的时间为负数,会报异常,因此,Calendar添加一天。

     

     

    JAVA WEB程序中添加定时器

    //这是我的定时器类,用来定时执行某段任务;

      package com.my.time;

      import java.text.ParseException;

      import java.text.SimpleDateFormat;

      import java.util.Date;

      import java.util.Timer;

      public class BugXmlTimer {

      public   Timer timer;

      public void timerStart(){

      timer = new Timer();

      Date datetime=new Date();

      Date midnightDate=new Date();

      SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");

      SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

      try {

      midnightDate = sdf2.parse(sdf1.format(datetime)+" 23:00:00");

      } catch (ParseException e) {

      // TODO Auto-generated catch block

      e.printStackTrace();

      }

      long in=midnightDate.getTime()-datetime.getTime();

      System.out.println("before task");

      //立刻执行,然后每隔30s执行一次

      timer.schedule(new BugXmlTimerTask(), 0,30000);

      }

      public void timerStop(){

      if(timer!=null)

      timer.cancel();

      }

      public static void main(String[] args){

      BugXmlTimer myTimer=new BugXmlTimer();

      // TODO Auto-generated method stub

      myTimer.timerStart();

      }

      }

      //这是执行任务的类,即每隔一段时间要做的事情在这里

      package com.my.time;

      import java.util.TimerTask;

      public class BugXmlTimerTask extends TimerTask {

      @Override

      public void run() {

      System.out.print("run task");

      }

      }

      //以下是出发定时操作的类,该类实现了ServletContextListener

      public class MyTimerListener implements ServletContextListener {

      private BugXmlTimer mytimer = new BugXmlTimer ();

      public void contextInitialized(ServletContextEvent event) {

      mytimer.timerStart();

      }

      public void contextDestroyed(ServletContextEvent event) {

      mytimer.timerStop();

      }

      }

      然后在web.xml里部署一下,即可在程序启动后运行定时器了!

      <listener>

      <listener-class>com.my.time.MyTimerListener </listener-class>

      </listener>

     

     

    Java 定时器退出解决方案

    项目中用到了 Timer 每隔一段时间进行一些操作,现在发现有时候莫名其妙地挂在这个计时器上的操作都不做了,用“JConsole”查看其中的线程以后,发现这个定时器线程也不在了(定时器创建的时候带了名字 Timer timer = new Timer("MyTimer"),所以直接能看到),由于日志太多,之前的日志已经找不到了,所以没有办法看是否是有异常发生以及发生在哪里。初步估计,是不是由于 TimerTask 中有异常抛出,如果定时器中没有处理的话,可能就会出问题。所以看了一下 java.util.Timer 的代码:

    1. // 在 TimerThread 中执行任务
    2. Timer.java:101:TimerThread
    3. // TimerThread 的入口
    4. // 这里只有一个 try/finally,如果 mainloop 中有异常抛出的话,肯定就结束运行。
    5. Timer.java:503:TimerThread.run()
    6. // 主循环体,其中只抓住了 InterruptedException 异常,其他的仍然往外抛。
    7. Timer.java:518:TimerThread.mainloop()

    从上面的代码可以看出,如果执行的任务中有其他任何运行时异常(RuntimeException)抛出,就必然导致定时器取消,也就是说挂在这个定时器上所有的人物都要被取消。明白了其内部处理机制,就要将其应用于实践,看如下例子:

    1. WrongTimerTask.java:
    2.  
    3. package org.supermmx.example.timer;
    4.  
    5. import java.util.Timer;
    6. import java.util.TimerTask;
    7.  
    8. /**
    9. * Wrong timer task.
    10. *
    11. * @author SuperMMX
    12. */
    13. public class WrongTimerTask extends TimerTask {
    14. private int count = 0;
    15.  
    16. public void run() {
    17. System.out.println(count);
    18. count ++;
    19. if (count == 3) {
    20. throw new NullPointerException("Test Exception");
    21. }
    22. }
    23.  
    24. public static void main(String[] args) {
    25. try {
    26. WrongTimerTask task = new WrongTimerTask();
    27. Timer timer = new Timer("TestTimer");
    28. timer.scheduleAtFixedRate(task, 0, 1000);
    29. } catch (Exception e) {
    30. e.printStackTrace();
    31. }
    32. }
    33. }

    上述代码中,每隔一秒钟打印一个递增的数值,等于 3 的时候抛一个空指针异常,结果怎么样呢?整个程序全部就退出了,就因为其中唯一的线程“TestTimer”退出了。跟前面所说的问题一模一样,只不过项目中还有很多别的线程,所以主程序并未退出。

    解决方法是什么呢?其实很简单,将 TimerTask 中整个 run() 方法 try 起来就可以了,保证它不再往外抛异常,代码如下:

    1. RightTimerTask.java:
    2.  
    3. package org.supermmx.example.timer;
    4.  
    5. import java.util.Timer;
    6. import java.util.TimerTask;
    7.  
    8. /**
    9. * Wrong timer task.
    10. *
    11. * @author SuperMMX
    12. */
    13. public class RightTimerTask extends TimerTask {
    14. private int count = 0;
    15.  
    16. public void run() {
    17. try {
    18. System.out.println(count);
    19. count ++;
    20. if (count == 3) {
    21. throw new NullPointerException("Test Exception");
    22. }
    23. } catch (Exception e) {
    24. e.printStackTrace();
    25. }
    26. }
    27.  
    28. public static void main(String[] args) {
    29. try {
    30. RightTimerTask task = new RightTimerTask();
    31. Timer timer = new Timer("TestTimer");
    32. timer.scheduleAtFixedRate(task, 0, 1000);
    33. } catch (Exception e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. }

    结果就是:异常也仍然抓住了,定时器也仍然可以继续工作,达到我们本来的目的。

    结论:使用 java.util.Timer 时候,在 java.util.TimerTask 的 run() 方法中实现具体操作的时候,必须要抓住所有异常,尤其是 RuntimeException,必须要保证不能往外抛异常,才能保证跟预想的运行情况一致。

     

    java定时器的应用举例。JAVA版本定时关机程序

    这个程序写的很简单,前段时间一个小MM说:从网上下载很多定时关机器都不好用,让我推荐一个。我下载了一些,觉得是不太好。当时也无聊就应承说我帮你写一个吧,功能很简单。

    于是java版的、粗糙的连界面都没有的定时关机器问世了。关机是利用java调用cmd来实现的,其实如果可以采用添加计划任务的方式来实现更好。不废话,上代码

    。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

    MyClock.java

    。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。


    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Scanner;
    import java.util.Timer;

    public class MyClock {
    public String checkTime() throws ParseException{
       System.out.println("请输入您要关机的时间,格式为mmddhhmm。例:01271010 >>>.............");
       Scanner sca=new Scanner(System.in);
       String time=sca.next();
       DateFormat df=new SimpleDateFormat("yyyyMMddHHmm");
       Date date=df.parse("2010"+time);
       //当输入时间在此刻之前 或者是输入字符数不对的时候再次提醒输入
       while(date.before(new Date())||!time.matches("\\d{8}")){
        date=df.parse("2010"+time);
        System.out.println("时间输入错误,请重新输入正确时间!");
        time=sca.next();
       }
       return "2010"+time;
    }
    public static void main(String[] args) throws ParseException{
       Timer timer=new Timer();
       Date date=null;
       DateFormat df=new SimpleDateFormat("yyyyMMddHHmmss");
       MyClock m=new MyClock();
       String str=m.checkTime()+"00";
       date=df.parse(str);
       System.out.println("关机时间输入成功,程序已经启动。请勿关闭窗口。");
       timer.schedule(new MyTask(),date);
    }
    }

    。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

    MyTask.java

    。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

    import java.io.*;
    import java.util.TimerTask;

    public class MyTask extends TimerTask {

    @Override
    public void run() {
       try {
          Process pro = Runtime.getRuntime().exec("cmd /c tsshutdn");
          BufferedReader br = new BufferedReader(new InputStreamReader(pro
            .getInputStream()));
          String msg = null;
          while ((msg = br.readLine()) != null) {
           System.out.println(msg);
          }
         } catch (IOException exception) {
         }
       this.cancel();
       System.exit(0);
    }

    }

     

    java定时器

    好多朋友用过Windows的任务计划,也有不少程序迷自己曾写过时钟报警、系统自动关机等趣味程序,可却很少有朋友在Web工程中实现过类似功能。
    当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次任务。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟 Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

    下面就Servlet侦听器结合Java定时器来讲述整个实现过程。要运用Servlet侦听器需要实现 javax.servlet.ServletContextListener接口,同时实现它的contextInitialized (ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入 contextInitialized,把销毁的过程置入contextDestroyed了。
    我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器,示例代码如下所示:
    import java.util.Timer;

    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServlet;

    public class ContextListener
    extends HttpServlet
    implements ServletContextListener {
    public ContextListener() {
    }

    private java.util.Timer timer = null;
    public void contextInitialized(ServletContextEvent event) {
    timer = new java.util.Timer(true);
    event.getServletContext().log("定时器已启动");
    timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000);
    event.getServletContext().log("已经添加任务调度表");
    }

    public void contextDestroyed(ServletContextEvent event) {
    timer.cancel();
    event.getServletContext().log("定时器销毁");
    }

    }
    以上代码中, timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000)这一行为定时器调度语句,其中MyTask是自定义需要被调度的执行任务(在我的财政数据中心项目中就是报表计算引擎入口),从 java.util.TimerTask继承,下面会重点讲述,第三个参数表示每小时(即60*60*1000毫秒)被触发一次,中间参数0表示无延迟。其它代码相当简单,不再详细说明。
    下面介绍MyTask的实现,上面的代码中看到了在构造MyTask时,传入了javax.servlet.ServletContext类型参数,是为记录Servlet日志方便而传入,因此需要重载MyTask的构造函数(其父类java.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,设置了每小时调度一次,因此如果想实现调度任务每24小时被执行一次,还需要判断一下时钟点,以常量C_SCHEDULE_HOUR表示(晚上12点,也即0点)。同时为防止24小时执行下来,任务还未执行完(当然,一般任务是没有这么长的),避免第二次又被调度以引起执行冲突,设置了当前是否正在执行的状态标志isRunning。示例代码如下所示:
    import java.util.*;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.*;

    public class MyTask extends TimerTask {
    private static final int C_SCHEDULE_HOUR = 0;
    private static boolean isRunning = false;
    private ServletContext context = null;

    public MyTask() {
    }
    public MyTask(ServletContext context) {
        this.context = context;
    }

    public void run() {
        Calendar cal = Calendar.getInstance();
        if (!isRunning) {
          if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {
            isRunning = true;
            context.log("开始执行指定任务");
            //TODO 添加自定义的详细任务,以下只是示例
            //系统定时接收邮件
            Email email=new Email();
            email.recieve();

            isRunning = false;
            context.log("指定任务执行结束");
          }
        }
        else {
          context.log("上一次任务执行还未结束");
        }
    }

    }
    到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:

    <listener>
    <listener-class>com.test.ContextListener</listener-class>
    </listener>

    当然,上面的com.test得换成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任务会在每晚12点至凌晨1点之间被执行。

    JAVA定时器使用

    【1】Java 定时器(java.util.Timer)有定时触发计划任务的功能,通过配置定时器的间隔时间,在某一间隔时间段之后会自动有规律的调用预先所安排的计划任务(java.util.TimerTask)。与每个 Timer 对象相对应的是单个后台线程,用于顺序地执行所有计时器任务。计时器任务应该迅速完成。如果完成某个计时器任务的时间太长,那么它会“独占”计时器的任务执行线程。因此,这就可能延迟后续任务的执行,而这些任务就可能“堆在一起”,并且在上述不友好的任务最终完成时才能够被快速连续地执行。另外,由于我们希望当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次报表计算引擎天等。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟Servlet上下文有关的监听器就最合适不过了,通过在工程的配置文件中加以 合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。   
        下面就Servlet监听器结合Java 定时器来讲述整个实现过程。要运用Servlet监听器需要实现javax.servlet.ServletContextListener接口,同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入 contextInitialized,把销毁的过程置入contextDestroyed了。

    package com.korby.servlet;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import com.korby.pub.TimerManager;
    /**
    * 启动定时器的监听器
    * @author korby
    * @version 1.0
    */

    public class TimerListener implements ServletContextListener {
        private TimerManager tm = null;
        public void contextInitialized(ServletContextEvent sce) {
          int day,hour,min,sec;     
           day = 26; hour = 16; min = 42; sec = 0;    
           tm = new TimerManager(day,hour,min,sec);
         }
        public void contextDestroyed(ServletContextEvent sce) {

            tm.destoryTimer();
         }
    }

    package com.korby.pub;
    import java.util.Timer;
    import java.util.Date;
    import java.util.Calendar;
    /**
    * 定时器
    * @author korby
    * @version 1.0
    */
    public class TimerManager {
         Timer t = null;
        public TimerManager(int day,int hour,int min,int sec) {
             time(day,hour,min,sec);
         }
        public void time(int day,int hour,int min,int sec){   
         Calendar c = Calendar.getInstance();
         c.set(Calendar.DAY_OF_MONTH,day);
         c.set(Calendar.HOUR_OF_DAY,hour);
         c.set(Calendar.MINUTE,min);
         c.set(Calendar.SECOND,sec);
         Date date = c.getTime();
         System.out.println(c.getTime());
         t= new Timer();
         MyTask mt = new MyTask();
         t.schedule(mt, date);
         }
        public void destoryTimer(){
         t.cancel();
         }
    }

    package com.korby.pub;

    import java.util.TimerTask;

    /**

    * 计划任务代码

    * @author korby

    * @version 1.0

    */

    public class MyTask extends TimerTask{

        public MyTask() { }

        /**

          * 任务块

         */

        public void run() {

             System.out.println("定时器RUN");

         }

    }

    在web.xml中设置一个监听器:

    <listener>

       <listener-class>com.korby.servlet.TimerListener</listener-class>

    </listener>

    【2】 java.util.Timer

    void cancel()  终止此计时器,丢弃所有当前已安排的任务。

    int purge()   从此计时器的任务队列中移除所有已取消的任务。

    void schedule(TimerTask task,Date time)  安排在指定的时间执行指定的任务。

    void schedule(TimerTask task,Date firstTime, long period)安排指定的任务在指定的时间开始进行重复的固定延迟执行。

    void schedule(TimerTask task,long delay)  安排在指定延迟后执行指定的任务。

    void schedule(TimerTask task,long delay, long period)安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。

    void schedule(TimerTask task,long delay, long period)安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。

    void scheduleAtFixedRate(TimerTask task,long delay, long period)安排指定的任务在指定的延迟后开始进行重复的固定速率执行。

    【3】java.util.TimerTask由 Timer 安排为一次执行或重复执行的任务。

    boolean cancel()          取消此计时器任务。

    abstract void run()          此计时器任务要执行的操作。

    long scheduledExecutionTime()       返回此任务最近实际 执行的已安排 执行时间。

     

     

    Java定时器状态错误:【java.lang.IllegalStateException:Timer already cancelled.】

    [10-3-5 13:14:41:729 CST] 1dd900b SystemErr     R java.lang.IllegalStateException: Timer already cancelled.
    [10-3-5 13:14:41:731 CST] 1dd900b SystemErr     R at java.util.Timer.sched(Timer.java:312)
    [10-3-5 13:14:41:731 CST] 1dd900b SystemErr     R at java.util.Timer.schedule(Timer.java:180)
    [10-3-5 13:14:41:731 CST] 1dd900b SystemErr     R at com.yourcompany.businesscomponent.utils.TimerRetrieveDb2Data.main(TimerRetrieveDb2Data.java:37)
    [10-3-5 13:14:41:731 CST] 1dd900b SystemErr     R at com.yourcompany.businesscomponent.service.YourBusinessNameFromDb2Service.controlTimerInManual(YourBusinessNameFromDb2Service.java:179)
    [10-3-5 13:14:41:731 CST] 1dd900b SystemErr     R at com.yourcompany.businesscomponent.action.YourBusinessNameAction.controlInManual(YourBusinessNameAction.java:617)
    [10-3-5 13:14:41:731 CST] 1dd900b SystemErr     R at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [10-3-5 13:14:41:731 CST] 1dd900b SystemErr     R at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    [10-3-5 13:14:41:732 CST] 1dd900b SystemErr     R at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    [10-3-5 13:14:41:732 CST] 1dd900b SystemErr     R at java.lang.reflect.Method.invoke(Method.java:324)
    [10-3-5 13:14:41:732 CST] 1dd900b SystemErr     R at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:280)
    [10-3-5 13:14:41:732 CST] 1dd900b SystemErr     R at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:216)
    [10-3-5 13:14:41:732 CST] 1dd900b SystemErr     R at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484)
    [10-3-5 13:14:41:732 CST] 1dd900b SystemErr     R at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
    [10-3-5 13:14:41:732 CST] 1dd900b SystemErr     R at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:525)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.servlet.StrictServletInstance.doService(StrictServletInstance.java:110)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.servlet.StrictLifecycleServlet._service(StrictLifecycleServlet.java:174)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.servlet.IdleServletState.service(StrictLifecycleServlet.java:313)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.servlet.StrictLifecycleServlet.service(StrictLifecycleServlet.java:116)
    [10-3-5 13:14:41:733 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.servlet.ServletInstance.service(ServletInstance.java:283)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.servlet.ValidServletReferenceState.dispatch(ValidServletReferenceState.java:42)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.servlet.ServletInstanceReference.dispatch(ServletInstanceReference.java:40)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.handleWebAppDispatch(WebAppRequestDispatcher.java:1036)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.dispatch(WebAppRequestDispatcher.java:544)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.forward(WebAppRequestDispatcher.java:210)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.srt.WebAppInvoker.doForward(WebAppInvoker.java:139)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.srt.WebAppInvoker.handleInvocationHook(WebAppInvoker.java:332)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.cache.invocation.CachedInvocation.handleInvocation(CachedInvocation.java:71)
    [10-3-5 13:14:41:734 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.srp.ServletRequestProcessor.dispatchByURI(ServletRequestProcessor.java:255)
    [10-3-5 13:14:41:735 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.oselistener.OSEListenerDispatcher.service(OSEListener.java:334)
    [10-3-5 13:14:41:735 CST] 1dd900b SystemErr     R at com.ibm.ws.webcontainer.http.HttpConnection.handleRequest(HttpConnection.java:56)
    [10-3-5 13:14:41:736 CST] 1dd900b SystemErr     R at com.ibm.ws.http.HttpConnection.readAndHandleRequest(HttpConnection.java:657)
    [10-3-5 13:14:41:736 CST] 1dd900b SystemErr     R at com.ibm.ws.http.HttpConnection.run(HttpConnection.java:463)
    [10-3-5 13:14:41:736 CST] 1dd900b SystemErr     R at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:937)
    ******************************
    【问题分析】
    如果定时器被执行cancel方法停止之后,再执行schedule()方法的话,会报此异常:【java.lang.IllegalStateException: Timer already cancelled.】
    【解决方案】
    请检查生成Timer的对象的方式,如果要调用schedule()方法的话,Timer对象需要new一个出来,看Timer的构造器就知道了,
    在Timer的构造器中才会调用线程的start()方法。所以:如果你在Timer对象调用cancel()之后,如果要调用schedule()方法,需要
    保证Timer的对象是new出来的。

     

     

    展开全文
  • 前言定时器线程池提供了定时执行任务的能力,即可以延迟执行,可以周期性执行。但定时器线程池也还是线程池,最底层实现还是ThreadPoolExecutor,可以参考我的另外一篇文章多线程–精通ThreadPoolExecutor。特点说明...

    前言

    定时器线程池提供了定时执行任务的能力,即可以延迟执行,可以周期性执行。但定时器线程池也还是线程池,最底层实现还是ThreadPoolExecutor,可以参考我的另外一篇文章多线程–精通ThreadPoolExecutor。

    特点说明

    1.构造函数

    public ScheduledThreadPoolExecutor(int corePoolSize) {

    // 对于其他几个参数在ThreadPoolExecutor中都已经详细分析过了,所以这里,将不再展开

    // 这里我们可以看到调用基类中的方法时有个特殊的入参DelayedWorkQueue。

    // 同时我们也可以发现这里并没有设置延迟时间、周期等参数入口。

    // 所以定时执行的实现必然在DelayedWorkQueue这个对象中了。

    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,

    new DelayedWorkQueue());

    }

    2.DelayedWorkQueue

    DelayedWorkQueue是在ScheduledThreadPoolExecutor的一个内部类,实现了BlockingQueue接口

    里面存放任务队列的数组如下:

    private RunnableScheduledFuture>[] queue =

    new RunnableScheduledFuture>[INITIAL_CAPACITY];

    public RunnableScheduledFuture> poll() {

    final ReentrantLock lock = this.lock;

    lock.lock();

    try {

    RunnableScheduledFuture> first = queue[0];

    // 这里有个getDelay,这是关键点,获取执行延时时间

    // 但是如果我们有延时设置的话,这就返回空了,然后就会调用take方法

    if (first == null || first.getDelay(NANOSECONDS) > 0)

    return null;

    else

    return finishPoll(first);

    } finally {

    lock.unlock();

    }

    }

    public RunnableScheduledFuture> take() throws InterruptedException {

    final ReentrantLock lock = this.lock;

    lock.lockInterruptibly();

    try {

    for (;;) {

    RunnableScheduledFuture> first = queue[0];

    if (first == null)

    available.await();

    else {

    // 获取延时时间

    long delay = first.getDelay(NANOSECONDS);

    if (delay <= 0)

    return finishPoll(first);

    first = null; // don't retain ref while waiting

    if (leader != null)

    available.await();

    else {

    Thread thisThread = Thread.currentThread();

    leader = thisThread;

    try {

    // 使用锁,执行延时等待。

    // 使用锁,执行延时等待。

    // 使用锁,执行延时等待。

    available.awaitNanos(delay);

    } finally {

    if (leader == thisThread)

    leader = null;

    }

    }

    }

    }

    } finally {

    if (leader == null && queue[0] != null)

    available.signal();

    lock.unlock();

    }

    }

    3.RunnableScheduledFuture

    在ScheduledThreadPoolExecutor内部有一个ScheduledFutureTask类实现了RunnableScheduledFuture,ScheduledFutureTask这个类采用了装饰者设计模式,在执行Runnable的方法基础上还执行了一些额外的功能。

    我们需要特别注意几个参数period、time。

    (1)time

    首先看一下time的作用,可以发现time是用于获取执行延时时间的,也就是delay是根据time生成的

    public long getDelay(TimeUnit unit) {

    return unit.convert(time - now(), NANOSECONDS);

    }

    (2)period

    这个参数不是说设置执行几个周期,而是用于判断是否需要按周期执行,以及执行周期,也就是本次执行与下次执行间隔的时间

    // 判断是否需要按周期执行,如果周期设置成0,不是无间隔执行,而是只执行一次,这个需要特别注意

    public boolean isPeriodic() {

    return period != 0;

    }

    private void setNextRunTime() {

    long p = period;

    if (p > 0)

    // 这里将周期加给time,这样获取的延迟时间就是周期时间了。

    time += p;

    else

    time = triggerTime(-p);

    }

    (3)执行

    public void run() {

    // 先判断是否为周期性的任务

    boolean periodic = isPeriodic();

    if (!canRunInCurrentRunState(periodic))

    cancel(false);

    else if (!periodic)

    // 如果不是周期性的,就执行调用父类的run方法,也就是构造函数中传入的Runnable对象的run方法。

    ScheduledFutureTask.super.run();

    // 在if的括号中先执行了任务

    else if (ScheduledFutureTask.super.runAndReset()) {

    // 如果是周期性的,就需要设置下次执行的时间,然后利用reExecutePeriodic方法,将任务再次丢入任务队列中。

    // 这里尤其需要注意的是if中的逻辑执行失败,如果没有捕捉异常,那么后面的逻辑就不会再执行了,也就是说中间有一次执行失败,后面这个周期性的任务就失效了。

    setNextRunTime();

    reExecutePeriodic(outerTask);

    }

    }

    总结

    ScheduledThreadPoolExecutor通过time参数,设置当前任务执行的等待时间,再通过period设置任务下次执行需要等待的时间。这两个参数都不是设置在线程池中的,而是携带在任务中的,这就可以把线程池和任务进行完全解耦。

    注意点:

    (1)任务的执行等待时间是在队列的take方法中的。

    (2)period参数设置成0,任务将只会执行一次,而不会执行多次

    (3)如果要自己实现周期性Task,周期性任务在执行过程中,一定要注意捕捉异常,否则某一次执行失败,将导致后续的任务周期失效,任务将不再继续执行。

    展开全文
  • Quartz定时器package quartz; import static org.quartz.CronScheduleBuilder.cronSchedule; import static org.quartz.JobBuilder.newJob; import static org.quartz.TriggerBuilder.newTrigger; import java....

    Java Quartz定时器

    package quartz;
    
    
    import static org.quartz.CronScheduleBuilder.cronSchedule;
    import static org.quartz.JobBuilder.newJob;
    import static org.quartz.TriggerBuilder.newTrigger;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    import org.quartz.CronTrigger;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerFactory;
    import org.quartz.impl.StdSchedulerFactory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    
    
    
    /**
     * job 作业配置
     * @author Administrator
     *
     */
    public class CronTriggerCfg {
    	
    	public void run() throws Exception {
    		Logger log =  LoggerFactory.getLogger(CronTriggerCfg.class);
    		//System.out.println("------- Initializing -------------------");
    		log.info("------- Initializing -------------------");
    
    
    		SchedulerFactory sf = new StdSchedulerFactory();
    		Scheduler sched = sf.getScheduler();
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    		
    		
    		log.info("------- 添加定时作业;每50秒执行一次  -------------------");
    		JobDetail job = newJob(DocUnfiledJob.class).withIdentity("job1", "group1").build();
    		CronTrigger trigger = newTrigger().withIdentity("trigger1", "group1")
    				.withSchedule(cronSchedule("0/50 * * * * ?")).build();
    		Date ft = sched.scheduleJob(job, trigger);
    		//System.out.println(job.getKey() + ">>>从: " + sdf.format(ft) + "开始执行 and repeat based on expression: "
    			//	+ trigger.getCronExpression());
    		log.info(job.getKey() + ">>>从: " + sdf.format(ft) + "开始执行 and repeat based on expression: "
    				+ trigger.getCronExpression());
    		
    		
    		
    		sched.start();
    	}
    
    
    	public static void main(String[] args) throws Exception {
    		CronTriggerCfg example = new CronTriggerCfg();
    		example.run();
    	}
    }

    • Scheduler:调度器。所有的调度都是由它控制。
    • Trigger: 定义触发的条件。例子中,它的类型是SimpleTrigger,每隔1秒中执行一次(什么是SimpleTrigger下面会有详述)。
    • JobDetail & Job: JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中,例子中是HelloQuartz。 为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题
    Job实现类:
    package quartz;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.quartz.JobKey;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    
    public class MyJob implements Job{
    	
    	Logger _log =  LoggerFactory.getLogger(MyJob.class);
    	
    	public MyJob(){
    		
    	}
    	
    	public void execute(JobExecutionContext context)
    	        throws JobExecutionException {
    	    	JobKey jobKey = context.getJobDetail().getKey();
    	    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    	    	
    	    	
    	    	_log.info("-------------------------作业开始: " + jobKey + " executing at " + sdf.format(new Date()));
    	    	
    	    	new Start().runDocUnfiled();//业务处理类
    	    	
    	    	_log.info("+++++++++++++++++++++++++作业结束: " + jobKey + " executing at " + sdf.format(new Date()));
    	    }
    	
    }

    业务处理:

    package quartz;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * 业务处理类
     * 
     * @author Administrator
     *
     */
    public class Start {
    	
    	Logger log = LoggerFactory.getLogger(Start.class);
    	
    	public void runUnfiled() {
    		log.info("-----业务开始------------");
    		System.out.println("业务处理");
    		log.info("--------业务结束-------");
    	}
    }


    项目中需要jar如下:下载地址

    log4j-1.2.16.jar

    quartz-2.2.3.jar

    quartz-jobs-2.2.3.jar

    slf4j-api-1.7.7.jar

    slf4j-log4j12-1.7.7.jar

    展开全文
  • 1、TimerTask //TimerTask实现30s从session中删除验证码 final Timer timer=new Timer(); timer.schedule(new TimerTask() { @Override public void run() { String yzm = (String) session....
  • java定时器初探

    2015-11-11 20:11:46
    从《thinking in java》了解到java原生的Times类有两个问题: (1)Timer是启动单个线程来处理所有的时间任务,如果一个任务耗时很久,那么如果在执行这个过程中,下个定时任务开始,就会对接下来的任务造成影响; ...
  • java 中的定时器设计

    2015-11-30 11:03:58
    1.如果需求简单的情况下,比如单线程下可以直接使用while循环配合Thread.sleep(1000)来暂停一秒 这里还是要对sleep有个认识,sleep的时候并没有释放任何资源,占用着CPU睡觉,睡完继续当前线程的...import java....
  • java定时器-固定时间间隔内执行操作

    千次阅读 2017-10-25 11:27:08
    java实现定时器操作
  • Java定时器(Timer)

    2021-06-19 16:48:42
    Timer和TimerTask是用于在后台线程中调度任务的java util类。简单地说,TimerTask是要执行的任务,Timer是调度器。 2.调度一次性任务 2.1 指定延迟后执行 让我们从简单地在定时器的帮助下运行单个任务开始: @Test ...
  • 使用定时器编程,在实时显示当前时间,每1秒时钟内容更新一次。 其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类,而具体的TimerTask需要由你自己来实现 思路 本人的思路是这样的。 ...
  • java之认识定时器Timer

    2017-10-31 21:57:48
    java定时器timer:基于给定的时间点、给点的时间间隔或者给定的执行次数自动执行的任务
  • java定时器的使用

    千次阅读 2014-12-16 17:00:29
    java定时器的使用(Timer) 1、在应用开发中,经常需要一些周期性的操作,比如每5分钟执行某一操作等。 对于这样的操作最方便、高效的实现方式就是使用java.util.Timer工具类。 privatejava.util.Timer timer; ...
  • 绍如何在JAVA WEB程序中添加定时器
  • 本文首先设计一个单次定时器Timer+TimerTask,然后再次基础上设计一个循环定时器
  • java实现自制定时器

    2017-07-17 20:40:49
    java实现自制定时器。 最近因为项目需求现在想封装一个定时器。 具体需要实现的功能为。 (1)直接调用一个方法就可以启动定时器。 (2)这个定时器支持设置定时时长,设置定时循环次数和定时的间隔时长。 (3...
  • 我的第一个java定时器

    千次阅读 2015-08-27 10:03:40
    接下来就去开发我的第一个java定时器吧,Java计时器实用程序允许您执行线程或任务在一个预先确定的将来的时间,并根据一组这些任务可以重复频率。 设计和实现一个计时器,会用到model-control-view(MVC)设计模式。 ...
  • Java定时器的使用(Timer) 原文链接:http://blog.csdn.net/ecjtuxuan/article/details/2093757 1、在应用开发中,经常需要一些周期性的操作,比如每5分钟执行某一操作等。 对于这样的操作最方便、高效的实现方式...
  • java定时器Timer对象

    2018-08-02 16:26:53
    //这是一个每间隔10秒运行一次的代码,期中日期可自定义该你想改的时间到...import java.text.*; import java.util.*; class LogTimerTask extends TimerTask{ public void run(){ System.out.println(new Sim...
  • java定时器的几种实现方式

    千次阅读 2020-05-08 18:19:58
    1 前言 在开始正题之前,先闲聊几句。有人说,计算机科学这个学科,软件方向研究到头就是数学,硬件方向...往底层实现看,又有多种定时器实现方案的原理、工作效率、数据结构可以深究…简单上手使用一个框架,并不能体
  • Java基础——定时器

    2013-10-14 23:38:11
    定时器:Timer import java.util.Timer; import java.util.TimerTask; public class TraditionalTimer { public static void main(String[] args) { Timer timer = new Timer(); TimerTask timeTask = n
  • Java--定时器问题

    2017-04-09 09:34:00
    定时器问题 ... 请设计一个定时器并实现以下三种基本行为,函数原型已给出,可使用任意编程语言设计数据结构及实现,并尽可能高效地支持大量定时器: // 添加定时器:经过特定时间间隔后执行目标...
  • Java定时器在Web中的应用

    千次阅读 2008-05-08 07:35:00
    首先介绍java定时器java.util.Timer)有定时执行计划任务的功能,通过设定定时器的间隔时间,会自动在此间隔时间后执行预先安排好的任务(java.util. TimerTask)如: 每隔一个小时执行任务 timer.schedule(TimerTask, ...
  • JAVA版本:jdk1.8,代码中有使用Lambda语法糖。 数据库:MySQL 框架:Spring Data 开发工具:IDEA 2017.3.2 Lombok PS: 1. 主要是结合Spring Boot一起使用,并在Spring Boot启动的时候一起启动...
  • java定时器Timer的使用

    千次阅读 2016-09-02 16:31:47
    定时器为守护进程 boolean flag=true; Timer timer1 =new Timer(flag); ③指定定时器的名字,方便指定停止  String name="TimerName2"; Timer timer2 =new Timer(name); ④指定定时器的名字,并指定为守护进程
  • #课程设计——定时器(201521123045 郑子熙) 1.团队课程设计博客链接 http://www.cnblogs.com/chendajia/p/7065730.html 2.个人负责模块或任务说明 负责main函数的编写。 负责TIme函数的编写,用于计算...
  • java中使用定时器

    2014-10-08 23:05:12
    基于线程池设计的 ScheduledExecutor。其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需 要注意的是,只有当任务的执行时间到来时,...
  • Redis 支持的 Java 客户端有哪些? 简单说明一下特点。 请简单描述一下 Jedis 的基本使用方法? Jedis 连接池链接方法有什么优点? 什么是分布式锁?有什么作用? 分布式锁可以通过什么来实现? 介绍一下分布式锁...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,100
精华内容 9,240
关键字:

java设计定时器

java 订阅