Java 每月定时器

发布于 2024-09-30 15:13:42 字数 1205 浏览 1 评论 0原文

我正在尝试创建一个将在每个月的同一天运行的计时器/计时器任务。我无法安排重复计时器,因为一个月的时间长度并不总是相同。

所以,这是我的解决方案:

public class MyTask extends TimerTask {
    public void run(){
        //do process file stuff

        if(scheduledExecutionTime() != 0){
            TimerHelper.restartMyTimer();
        }
    }
}

public class TimerHelper {
    public static HashTable timersTable = new HashTable();

    public static void restartMyTimer(){
        Calendar runDate = Calendar.getInstance();
        runDate.set(Calendar.DAY_OF_MONTH, 1);
        runDate.set(Calendar.HOUR_OF_DAY, 4);
        runDate.set(Calendar.MINUTE, 0);
        runDate.add(Calendar.MONTH, 1);//set to next month

        MyTask myTask = new MyTask();
        Timer myTimer = new Timer();

        myTimer.schedule(myTask, runDate.getTime());

        timersTable = new HashTable();//keeping a reference to the timer so we 
        timersTable.put("1", myTimer);//have the option to cancel it later
    }
}

我想我会遇到的问题是,因为第一个 TimerTask 创建了第二个 Timer,第一个 Timer 会因为创建了第二个 Timer 而被保留吗?在第一个计时器上的代码完成后,垃圾收集会处理该线程和对象吗?随着时间的推移,我不想建立一堆不做任何事情但又没有被删除的线程。也许我对线程和计时器的工作原理没有正确的理解...

只要我不必使用第三方 JAR,我就可以接受其他创建每月计时器的方法的建议。

谢谢!

I am trying to create a Timer/TimerTask that will run the same day of every month. I can't schedule a repeating Timer because a month won't always be the same lenght of time.

So, here is my solution:

public class MyTask extends TimerTask {
    public void run(){
        //do process file stuff

        if(scheduledExecutionTime() != 0){
            TimerHelper.restartMyTimer();
        }
    }
}

public class TimerHelper {
    public static HashTable timersTable = new HashTable();

    public static void restartMyTimer(){
        Calendar runDate = Calendar.getInstance();
        runDate.set(Calendar.DAY_OF_MONTH, 1);
        runDate.set(Calendar.HOUR_OF_DAY, 4);
        runDate.set(Calendar.MINUTE, 0);
        runDate.add(Calendar.MONTH, 1);//set to next month

        MyTask myTask = new MyTask();
        Timer myTimer = new Timer();

        myTimer.schedule(myTask, runDate.getTime());

        timersTable = new HashTable();//keeping a reference to the timer so we 
        timersTable.put("1", myTimer);//have the option to cancel it later
    }
}

The problem I think I'm going to run into is that because the first TimerTask creates the second Timer, will the first Timer be kept around because it created the second? After the code finishes on the first Timer, will that thread and object be taken care of by garbage collection? Over time I don't want to build up a bunch of Threads that aren't doing anything but aren't being removed. Maybe I don't have a proper understanding of how Threads and Timers work...

I'm open to suggestions of other ways to create a monthly timer as long as I don't have to use third party JARs.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

嘿哥们儿 2024-10-07 15:13:43

只使用计划的计时器怎么样,当您完成当前计划的任务计划时,下一步:

 ScheduledExecutorService es = Executors.newSingleThreadScheduledExecutor();

 es.schedule(new MyTask(), numberOfDaysRemaining(), TimeUnit.DAYS);


class MyTask implements Runnable {
 public void run() {
  try {
   // do it
  } finally {
   es.schedule(new MyTask(), numberOfDaysRemaining(), TimeUnit.DAYS);
  }
 }
}

您可以使用 JodaTime 更容易地进行日期计算。

What about just using a scheduled timer, and as you complete the currently scheduled task schedule the next:

 ScheduledExecutorService es = Executors.newSingleThreadScheduledExecutor();

 es.schedule(new MyTask(), numberOfDaysRemaining(), TimeUnit.DAYS);


class MyTask implements Runnable {
 public void run() {
  try {
   // do it
  } finally {
   es.schedule(new MyTask(), numberOfDaysRemaining(), TimeUnit.DAYS);
  }
 }
}

You can use JodaTime to do the date calculations more easily.

与之呼应 2024-10-07 15:13:43

最简单的解决方案可能是使用 cron 或等效的方法来安排独立程序的执行...

the simplest solution might be to use cron or equivalent to schedule a stand-alone program execution...

听,心雨的声音 2024-10-07 15:13:43

Quartz 调度程序 库允许您根据 cron 作业表达式进行调度。

The Quartz scheduler library allows you to schedule based on cron job expressions.

爱你不解释 2024-10-07 15:13:43

我认为您还可以创建一个线程并从 DelayQueue 来执行此操作。但它并不像 ScheduledExecutorService 那么容易。

I think you could also create one single thread and read from DelayQueue to do this. But it's not as easy as ScheduledExecutorService.

蓝海 2024-10-07 15:13:43

为什么每次都需要重新创建Timer?计时器只是带有粘合代码的线程。取消它会导致该计时器上运行的其他任务终止。

最好使用以下内容:

MonthlyTimer extends Timer {
     public void execute(TimerTask task, Date date, int dayOfMonth) {
          this.schedule(new TimerTaskWithCallback(task, dayOfMonth, this), date);
     }

     void taskCallback(TimerTaskWithCallback task) {
          this.schedule(new TimerTaskWithCallback(task.getImpl()), nextDate(task.getDayOfMonth())); //next date could be used from Oscar's post.
     }
}

TimerTaskWithCallback 仅在原始任务执行后执行 MonthlyTimer.taskCallback。可以有“try { } catch {} finally {}”粘合代码。

Why do you need to recreate Timer every time? Timer is just thread with glue code around. Cancelling it cause terminating of other tasks running on that Timer.

It is better to use the following:

MonthlyTimer extends Timer {
     public void execute(TimerTask task, Date date, int dayOfMonth) {
          this.schedule(new TimerTaskWithCallback(task, dayOfMonth, this), date);
     }

     void taskCallback(TimerTaskWithCallback task) {
          this.schedule(new TimerTaskWithCallback(task.getImpl()), nextDate(task.getDayOfMonth())); //next date could be used from Oscar's post.
     }
}

TimerTaskWithCallback just executes MonthlyTimer.taskCallback after original task execution. Could have "try { } catch {} finally {}" glue code.

情话难免假 2024-10-07 15:13:42

如果您担心创建不需要的对象,您始终可以创建一个对象,该对象又创建/“销毁”所有引用,因此创建的对象可能会被GC。

最坏的情况是,一年内你会拥有 12 个不需要的物品,我认为这是可以忍受的。不过你的担心还是有道理的。

这是我在执行结束时遵循乔尔建议的时间表的尝试。请注意,当前的计时器已被新的计时器替换,因此计时器和计时器任务都可以被GC。

package monthly.schedule;

import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;
import java.util.Calendar;

public class MonthlyTimer { 
    // What to do
    private final Runnable whatToDo;

    // when 
    private final int dayOfMonth;
    private final int hourOfDay;

    // The current timer
    private Timer current = new Timer();//to avoid NPE

    public void cancelCurrent() { 
        current.cancel();// cancel this execution;
        current.purge(); // removes the timertask so it can be gc'ed
    }

    // create a new instance
    public static MonthlyTimer schedule( Runnable runnable, int dayOfMonth, int hourOfDay ) { 
        return new MonthlyTimer( runnable, dayOfMonth, hourOfDay );
    }

    private MonthlyTimer(Runnable runnable, int day, int hour ) { 
        this.whatToDo = runnable;
        this.dayOfMonth = day;
        this.hourOfDay = hour;
        schedule();
    }
    // Schedules the task for execution on next month. 
    private void schedule() { 
        // Do you mean like this?
        cancelCurrent();
        current = new Timer(); // assigning a new instance
        // will allow the previous Timer to be gc'ed

        current.schedule( new TimerTask() { 
            public void run() { 
                try { 
                    whatToDo.run();
                } finally { 
                    schedule();// schedule for the next month
                }
            }
        } , nextDate() );           
    }
    // Do the next date stuff
    private Date nextDate() { 
        Calendar runDate = Calendar.getInstance();
        runDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        runDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
        runDate.set(Calendar.MINUTE, 0);
        runDate.add(Calendar.MONTH, 1);//set to next month
        return runDate.getTime();
    }
}

class UseIt { 
    public static void main( String [] args ) { 
        int the1st = 1;
        int at16hrs = 16;

        MonthlyTimer t = MonthlyTimer.schedule( new Runnable() { 
            public void run() { 
                System.out.println( "Hola" );
            }}, the1st, at16hrs );

        // will print "Hola" every 1st at 16:00 hrs.
       // if needed you can cancel with: 
        t.cancelCurrent();

    }
}

If what worries you is to create unneeded objects you can alway create an object which in turn creates/"destroy" all the references, so the objects created may be gc'ed.

In the worst case, you'll have 12 unneeded objects in a year, which, I think is bearable. Still your concern is valid.

Here's my attempt following Joel's suggestion of schedule at the end of the execution. Notice, the current Timer is replaced by a new one, so, both, the timer and the timer task could be gc'ed.

package monthly.schedule;

import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;
import java.util.Calendar;

public class MonthlyTimer { 
    // What to do
    private final Runnable whatToDo;

    // when 
    private final int dayOfMonth;
    private final int hourOfDay;

    // The current timer
    private Timer current = new Timer();//to avoid NPE

    public void cancelCurrent() { 
        current.cancel();// cancel this execution;
        current.purge(); // removes the timertask so it can be gc'ed
    }

    // create a new instance
    public static MonthlyTimer schedule( Runnable runnable, int dayOfMonth, int hourOfDay ) { 
        return new MonthlyTimer( runnable, dayOfMonth, hourOfDay );
    }

    private MonthlyTimer(Runnable runnable, int day, int hour ) { 
        this.whatToDo = runnable;
        this.dayOfMonth = day;
        this.hourOfDay = hour;
        schedule();
    }
    // Schedules the task for execution on next month. 
    private void schedule() { 
        // Do you mean like this?
        cancelCurrent();
        current = new Timer(); // assigning a new instance
        // will allow the previous Timer to be gc'ed

        current.schedule( new TimerTask() { 
            public void run() { 
                try { 
                    whatToDo.run();
                } finally { 
                    schedule();// schedule for the next month
                }
            }
        } , nextDate() );           
    }
    // Do the next date stuff
    private Date nextDate() { 
        Calendar runDate = Calendar.getInstance();
        runDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        runDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
        runDate.set(Calendar.MINUTE, 0);
        runDate.add(Calendar.MONTH, 1);//set to next month
        return runDate.getTime();
    }
}

class UseIt { 
    public static void main( String [] args ) { 
        int the1st = 1;
        int at16hrs = 16;

        MonthlyTimer t = MonthlyTimer.schedule( new Runnable() { 
            public void run() { 
                System.out.println( "Hola" );
            }}, the1st, at16hrs );

        // will print "Hola" every 1st at 16:00 hrs.
       // if needed you can cancel with: 
        t.cancelCurrent();

    }
}
深爱成瘾 2024-10-07 15:13:42

我建议简单地使用 Quartz 并通过 Quartz 调度作业。 quartz-scheduler.org/docs/tutorials/crontrigger.html" rel="noreferrer">CronTrigger 允许您指定希望在每月的第一天执行作业,并让 Quartz处理时序逻辑。

这里是如何使用 CronTrigger 的进一步代码示例

Quartz 是一个极其简单易用的库。

I would suggest simply using Quartz and scheduling jobs via a CronTrigger which will allow you to specify you want the job executed on the first day-of-the-month, and let Quartz handle the timing logic.

Here is a further code example of how to use CronTrigger.

Quartz is a dead-simple easy library to use.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文