3

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             
        }
    }
amit
  • 175,853
  • 27
  • 231
  • 333
SNV7
  • 2,563
  • 5
  • 25
  • 37

13 Answers13

5

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.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Would this alternative play nice within a managed environment? would it synchronously block the current thread? if the answer to either question is "yes", I'd recommend against it, preferring an asynchronous service external to the container - like Quartz. – Óscar López Oct 12 '12 at 21:13
  • @ÓscarLópez Quote OP: "I'm tryng to write a simple Java program". Adapt your advice to the context, please. – Marko Topolnik Oct 12 '12 at 21:17
  • I ask because the question is tagged java-ee , so I assumed that the "simple application" lives inside a JEE container - making it not-so-simple after all. – Óscar López Oct 12 '12 at 21:27
  • 1
    @ÓscarLópez It was also tagged "eclipse" and "algorithm", so go figure. I googled around for Quartz and the second hit is [this page](http://java.dzone.com/articles/why-you-shouldnt-use-quartz): "Why you shouldn't use Quartz Scheduler". – Marko Topolnik Oct 12 '12 at 21:28
2

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.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • The second paragraph is news to me. Care to give a source? – meriton Oct 12 '12 at 20:37
  • That covers the EJB case, but does that hold for any web container? For instance, the Servlet specification talks about "application created threads" (Servlet 3.0 spec, page 104). – meriton Oct 12 '12 at 20:46
  • No threads should be created, destroyed or manipulated in any way inside a managed environment. Even though you _can_, you _should not_ - doing so messes with the container's ability to control resources – Óscar López Oct 12 '12 at 20:49
  • @meriton Just consider what it takes to make application undeployment predictably safe. – Marko Topolnik Oct 12 '12 at 20:51
  • @MarkoTopolnik: If Quartz can stop a worker thread when the context is destroyed, so can I ... or were you referring to something else? – meriton Oct 12 '12 at 21:00
  • 1
    @meriton We are talking about the same thing. I don't claim you are not allowed, or shouldn't, create your threads in a servlet. I am emphasizing the possible consequences, which explains why someone else may claim that you shouldn't do it. – Marko Topolnik Oct 12 '12 at 21:04
1

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

amit
  • 175,853
  • 27
  • 231
  • 333
1

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

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
1

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.
Radu
  • 1,044
  • 3
  • 12
  • 35
0

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) {}
}
Tom G
  • 3,650
  • 1
  • 20
  • 19
0

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

jmj
  • 237,923
  • 42
  • 401
  • 438
0

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

}
Suzan Cioc
  • 29,281
  • 63
  • 213
  • 385
0

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);
}
}
Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
0

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

quartzde
  • 598
  • 2
  • 8
0

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"

Community
  • 1
  • 1
David Blevins
  • 19,178
  • 3
  • 53
  • 68
0

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();
        }
    }
PbxMan
  • 7,525
  • 1
  • 36
  • 40
0

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());
    }   
}
PbxMan
  • 7,525
  • 1
  • 36
  • 40