Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Monthly Timer

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!

like image 946
bmeding Avatar asked Nov 05 '10 14:11

bmeding


People also ask

How do you schedule a Timer in Java?

Java Timer schedule() methodThe schedule (TimerTask task, Date time) method of Timer class is used to schedule the task for execution at the given time. If the time given is in the past, the task is scheduled at that movement for execution.

Can you set a Timer in Java?

Timer is a utility class that can be used to schedule a thread to be executed at certain time in future. Java Timer class can be used to schedule a task to be run one-time or to be run at regular intervals.

How do you repeat a Timer in Java?

Use timer. scheduleAtFixedRate() to schedule it to recur every two seconds: Schedules the specified task for repeated fixed-rate execution, beginning at the specified time. Subsequent executions take place at approximately regular intervals, separated by the specified period.

What is TimerTask in Java?

TimerTask is an abstract class defined in java. util package. TimerTask class defines a task that can be scheduled to run for just once or for repeated number of time. In order to define a TimerTask object, this class needs to be implemented and the run method need to be overridden.


2 Answers

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();

    }
}
like image 167
OscarRyz Avatar answered Sep 29 '22 08:09

OscarRyz


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.

like image 43
matt b Avatar answered Sep 29 '22 07:09

matt b