views:

358

answers:

6

I have an app that needs to do one thing, and one thing only, on a schedule and it will be able to calculate easily the time it next needs to run. It may not need to run this task for days or months from now, but will probably be active in every other respect every few milliseconds.

I'm looking for a simple lightweight approach to scheduling that one task to run.

+11  A: 

On Unix, have a look at the system tools cron or at.

On Windows, there is a job scheduler in the system settings.

For a simple Java-only solution, try the Timer API.

For a more complex Java-only solution, have a look at quartz.

Aaron Digulla
Well that's kind of obvious.
Simon Gibbs
And your point is?
Aaron Digulla
Sure, mentioning those might be useful for newbie Googlers with a similar problem, but I need to do one thing only on a schedule so all of those look heavyweight. I don't think the answer considers that aspect of the posted question.
Simon Gibbs
Adding Timer is a useful edit... thanks.
Simon Gibbs
+4  A: 

If your java app is intended to be running continuously then you can use the Timer class to schedule execution

If your app isn't going to be running continuously then the other answers are correct. cron / task scheduler are the way to go.

Glen
better link: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Timer.html
Kevin Panko
@Kevin Thanks for that. I forget about the frames problem on the Java API site every time I post a link. Must be more careful in the future.
Glen
A: 

Just use java.util.concurrent, it has a scheduled execution widget. You'd need to add a guard condition to prevent excessive runs, or else add the next execution at the end of the current one.

Simon Gibbs
I would follow Aaron Digulla's advice if I were you. It looks to me like the classes and functionality in java.util.concurrent are made for thread scheduling, not far-in-the-distant-future task scheduling, and it would probably be extremely non-optimal. Scheduling in that sense means figuring out how several tasks will take turns to run on one CPU/core (in chunks of milliseconds), not scheduling a task several days from now.
Ricket
+1  A: 

Well, you can schedule a cron job if you need your app to run at certain times. Or, you can write a simple class that will schedule itself for certain times. Since I'm not aware of any library out there (never really needed to look for one), I wrote a class long ago to schedule a task for myself. Hope it helps and in ballpark:

import java.util.*;

public abstract class TimeMonitor extends Thread
    {
        protected double execution_time;
        protected boolean execute_at_startup;

        public TimeMonitor()
            {
                execute_at_startup = false;
            }

        public TimeMonitor(double time)
            {
                execution_time = time;
                execute_at_startup = false;
            }

        public void startTimer()
            {
                setPriority(Thread.MIN_PRIORITY);
                start();
            }

        public void setTime(double time)
            {
                execution_time = time;
            }

        public void executeAtStartup()
            {
                execute_at_startup = true;
            }

        public void run()
            {
                if (execute_at_startup)
                    doTimedAction();

                while (true)
                    {
                        long runtime = (long)(execution_time * 3600 * 1000);
                        long now     = getTime();
                        long sleep   = 0;

                        // Calculate how long to way until first run
                        if (runtime > now)
                            sleep = runtime - now;
                        else
                            sleep = 24 * 3600 * 1000 - now + runtime;

                        try
                            {
                                Thread.sleep(sleep);
                            }
                        catch (InterruptedException e)
                            {
                                logError("Wait thread has been interrupted.", e);
                                continue;
                            }

                        doTimedAction();
                    }
            }

        /**
         * Calculates number of milliseconds from start of the day.
         *
         * @return Number of milliseconds.
         */
        private long getTime()
            {
                Calendar cal = Calendar.getInstance();
                int hours   = cal.get(Calendar.HOUR_OF_DAY);
                int minutes = cal.get(Calendar.MINUTE);
                int seconds = cal.get(Calendar.SECOND);
                int millis  = cal.get(Calendar.MILLISECOND);

                return (hours * 3600 + minutes * 60 + seconds) * 1000 + millis;
            }

        private void doTimedAction()
            {
                try
                    {
                        performAction();
                    }
                catch (Throwable e)
                    {
                        logError("An error occured during timed execution.", e);
                    }
            }

        /**
         * This method will be called when an error or a warning occures.
         *
         * @param msg
         * @param e
         */
        protected void logError(String msg, Throwable e)
            {
                System.out.println(msg);
                e.printStackTrace();
            }

        /**
         * Action to be performed when scheduled time happens.
         */
        protected abstract void performAction();
    }

Extend to use it like so:

        TimeMonitor archiver = new TimeMonitor()
            {
                protected void performAction()
                    {
                        // Do the task
                    }
            };

        archiver.setTime(16.5); // Run at 4:30pm
        archiver.startTimer();
Daniil
+1  A: 

Quartz is good for this type of thing. It's supported well in Spring apps as well.

stevedbrown