SNV7
SNV7

Reputation: 2593

Run Java code once every hour

I'm tryng to write a simple Java program that runs some code every hour when the minute hand is at 20. The issue is that that the way I'm doing it is incredibly CPU intensive. I'm familiar with Quartz but I'm looking for a much simpler solution, any ideas?

    boolean run = true;
    while(run){
        Calendar calendar = new GregorianCalendar();
        int minute = calendar.get(Calendar.MINUTE);
        if(minute == 20){
            //Do some Stuff             
        }
    }

Upvotes: 3

Views: 8988

Answers (13)

Óscar López
Óscar López

Reputation: 235984

Be aware that if your application is running inside a managed environment (a web or ejb container) you're not allowed to use Thread.sleep() or any other thread-related operations, for that matter, take a look at the EJB restrictions page. I warn about this because the question is tagged java-ee, so the "simple application" might not be so simple after all - if it's running inside a Java EE container there are additional considerations to take care of.

If you're building an enterprise-grade application, forget about Thread.sleep(). Go for a full-fledged job scheduler, Use Quartz, it's an open source and extremely mature and reliable product. Or use Obsidian Scheduler, a feature-rich commercial scheduler with more out-of-the-box features than Quartz.

A lightweight alternative to a full-fledged scheduler (but suitable for running inside a container) would be to use the Timer service.

Upvotes: 2

Radu
Radu

Reputation: 1104

I would suggest that you remove the scheduling logic from your java program.
By doing this you are able to focus only on what you want your program to do and leave the scheduling part to the OS.
Also, say for example you decide at some point to write a c++ program that does what your java code does know, you won't have to implement the cron logic in your new program

That being said:

  • for Linux you have crontab
  • for Windows you have windows task schedule
  • for Mac, I am not sure, but given the fact it is UNIX based cron should be present.

Upvotes: 1

PbxMan
PbxMan

Reputation: 7625

Yet even another example with the things learned today.

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class SchedulerExample2 implements Runnable{

    public static void main(String args[]) {

        Calendar due = Calendar.getInstance();
        due.set(Calendar.MILLISECOND, 0);
        due.set(Calendar.SECOND, 0);
        due.set(Calendar.MINUTE, 20);
        if (due.before(Calendar.getInstance())) {
            due.add(Calendar.HOUR, 1);
        }
        long milliSecondsToNextOcurrence =  due.getTimeInMillis() - new Date().getTime();
        final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
        ShedulerExample task = new  ShedulerExample();
        s.scheduleAtFixedRate(task, milliSecondsToNextOcurrence, 60*60*1000, TimeUnit.MILLISECONDS);
    }

    @Override
    public void run() {
            System.out.println("hola->"+new Date());
    }   
}

Upvotes: 0

PbxMan
PbxMan

Reputation: 7625

Another example

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestHour {

    private static final int MINUNTE = 20;

    public static void main(String args[]) {
        while (true) {
            SimpleDateFormat bartDateFormat = new SimpleDateFormat("mm");
            Date date = new Date();
            int currentMin = new Integer(bartDateFormat.format(date))
                    .intValue();
            if (currentMin < MINUNTE) {
                sleepMinutes(MINUNTE - currentMin);
            } else if (currentMin > MINUNTE) {
                sleepMinutes(60 - currentMin + MINUNTE);
            } else {
                // DO SOMETHING EVERY HOUR
                System.out.println("come on do it!!!");
                sleepMinutes(60);
            }
        }
    }

    private static void sleepMinutes(int minutes) {
        try {
            System.out.println("Sleeping for " + minutes);
            Thread.sleep(minutes * 1000*60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

Upvotes: 0

Marko Topolnik
Marko Topolnik

Reputation: 200138

A simple solution is to use the Executors framework:

final ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
s.scheduleAtFixedRate(task, secondsToFirstOccurence, 60*60, TimeUnit.SECONDS);

And use some logic to find out secondsToFirstOccurence. This will probably involve a Calendar instance, but would be much more convenient with JodaTime.

Upvotes: 5

Suzan Cioc
Suzan Cioc

Reputation: 30097

1) On first entry calculate next due time.

2) Use java.util.Timer.schedule()

3) Reschedule each run.

Code

package tests;

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

public class App201210130040 {


private static Timer timer = new Timer(false);

public static void schedule() {
    Calendar due = Calendar.getInstance();
    due.set(Calendar.MINUTE, 20);
    if( due.before(Calendar.getInstance()) ) {
        due.add(Calendar.HOUR, 1);
    }

    System.out.println("Scheduled to " + due.getTime().toString());

    timer.schedule(new TimerTask() {

        @Override
        public void run() {

            System.out.println("due");

            schedule();
        }

    }, due.getTime());

}


public static void main(String[] args) {
    schedule();
}

}

Upvotes: 0

David Blevins
David Blevins

Reputation: 19368

So definitely the ScheduledExecutorService is fantastic as many of the other answers state.

In the event you're in a Java EE 6 server, you could have some fun with @Schedule and ScheduleExpression

See Have an EJB schedule tasks with "crontab syntax"

Upvotes: 0

quartzde
quartzde

Reputation: 638

Use something like this

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 20);
calendar.set(Calendar.MINUTE, 20);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
Timer timer = new Timer();
timer.schedule(new SomeTask(), time);

and then reschedule

Upvotes: 0

Amit Deshpande
Amit Deshpande

Reputation: 19185

You should have a look at ScheduledExecutorService

class BeeperControl {
private final ScheduledExecutorService scheduler = 
   Executors.newScheduledThreadPool(1);

public void beepForAnHour() {
    final Runnable beeper = new Runnable() {
            public void run() { System.out.println("beep"); }
        };
    final ScheduledFuture<?> beeperHandle = 
        scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
    scheduler.schedule(new Runnable() {
            public void run() { beeperHandle.cancel(true); }
        }, 60 * 60, SECONDS);
}
}

Upvotes: 0

Olaf Dietsche
Olaf Dietsche

Reputation: 74018

Look at java.util.Timer method scheduleAtFixedRate().

Upvotes: 1

Jigar Joshi
Jigar Joshi

Reputation: 240860

Schedule a cron job for the method that you want to execute hourly rather going for blocking sleep() call, Use some scheduling framework like quartz

Upvotes: 0

Tom G
Tom G

Reputation: 3650

Put your code in an infinite while and use

Thread.sleep(3600000);

Start the execution at 20 after

Example

while(1==1) {
    //Your code here
    try{
         Thread.sleep(3600000);
    }
    catch (Exception e) {}
}

Upvotes: 0

amit
amit

Reputation: 178411

You might be looking for Thread.sleep() between calls

Upvotes: 1

Related Questions