20

I have a thread that needs to be executed every 10 seconds. This thread contains several calls (12 - 15) to a database on another server. Additionally, it also accesses around 3 files. Consequently, there will be quite a lot of IO and network overhead.

What is the best strategy to perform the above?

One way would be to use the sleep method along with a while loop, but that would be a bad design.

Will a class similar to Timer be helpful in this case? Also, would it be better to create a couple of more threads (one for IO and one for JDBC), instead of having them run in one thread?

Epitaph
  • 3,128
  • 10
  • 34
  • 43
  • Why is the sleep a bad design? Granted it won't be every 10 seconds, rather every 10+n seconds. But you can't guarantee 10 seconds anyway if one of the passes takes 12 seconds to complete. If you're just trying to minimize load on the server, it makes little difference whetehr it a sleep or timer. – paxdiablo Jan 09 '09 at 01:41
  • I was referring the sleep along with the while loop, as a bad design. Since, it might not be very intuitive to decide on the when and how of terminating the thread. – Epitaph Jan 09 '09 at 01:53

3 Answers3

52

I find that a ScheduledExecutorService is an excellent way to do this. It is arguably slightly more complex than a Timer, but gives more flexibility in exchange (e.g. you could choose to use a single thread or a thread pool; it takes units other than solely milliseconds).

ScheduledExecutorService executor =
    Executors.newSingleThreadScheduledExecutor();

Runnable periodicTask = new Runnable() {
    public void run() {
        // Invoke method(s) to do the work
        doPeriodicWork();
    }
};

executor.scheduleAtFixedRate(periodicTask, 0, 10, TimeUnit.SECONDS);
Greg Case
  • 46,881
  • 3
  • 27
  • 21
  • If you were not using a single threaded executor, I might be inclined to wrap the doPeriodicWork() call in a "synchronized (this)" block just to be safe. – Evan Jan 09 '09 at 02:58
  • That would certainly protect; declaring doPeriodicWork as synchronized would accomplish the same thing and probably be a little cleaner. That being said, there are probably smaller critical sections within doPeriodicWork that could be protected individually if moving to a thread pool. – Greg Case Jan 09 '09 at 03:10
  • @GregCase: If you change `periodicTask` while `executor` is running, how do you get `executor` to update itself to use the latest `periodicTask` at runtime? –  Aug 04 '15 at 12:12
  • @ThreaT: There's no way to swap out the Runnable instance directly. You have 2 options: Cancel (using the ScheduledFuture returned by schedule) and re-submit with the new Runnable, or set up your Runnable instance to have state such that it delegates to another object instance then swap that object instance out on the fly. Note if you do this your Runnable will likely not be able to be an anonymous inner class like the example in the answer; you will need to at a minimum declare a field storing the delegate instance and keep the reference around somewhere to be able to update that field. – Greg Case Aug 04 '15 at 15:27
5

One option is to create a ScheduledExecutorService to which you can then schedule your job:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ex.scheduleWithFixedDelay(...);

If you did decide to have multiple threads, then you can create a ScheduledExecutorService with more threads (again, via the Executors class).

In terms of how many threads and what you put in each thread, in terms of performance, I'd say this depends on:

  • for your particular application, can one thread genuinely "do work" while another one is waiting for I/O?
  • would your multiple threads ultimately "thrash the same resource" (e.g. read from files in different locations on the same dsk) and thus slow one another down, or would they be simultaneously hitting different resources?
Neil Coffey
  • 21,615
  • 7
  • 62
  • 83
4

Have a look at the Timer and TimerTask classes. They are exactly what you want.

You can make a TimerTask implementation that takes your thread object in a constructor.

The run method will then call the threads run method.

// Perhaps something like this
Timer t = new Timer();
t.scheduleAtFixedRate(yourTimerTask, 0, 10 * 1000);
// Hopefully your task takes less than 12 seconds
jjnguy
  • 136,852
  • 53
  • 295
  • 323
  • 10 Chars is just a suggestion! – jjnguy Jan 09 '09 at 01:47
  • I just tried to enter "! ." and I get the dreaded "Please enter at least 10 characters." under the input box when I click on AddComment. It doesn't actually enter the comment. How'd you do that?? – paxdiablo Jan 09 '09 at 04:13
  • If you type !. you can trick the system. It seems to count space as a character and then remove extra ones when it feels like it. – jjnguy Jan 09 '09 at 04:14
  • Yeah, you can't put spaces at the start or end, they need to be in the middle! Who wrote this crap? :-) – paxdiablo Jan 09 '09 at 04:16