This will be a very short post, and I’m mostly writing it just so it sticks in my head better.
Common Use Cases
There are many times when you may find that you need to regularly run a task in Java. Here are a few common examples:
- You have a cache you need to refresh every X minutes to power a dashboard or something similar.
- You need to prune old files from a file system once an hour.
- You need to regularly update stats counters for monitoring.
There are a lot of ways to do this, but the recommended approach would be to use a scheduled executor. Now… this part is easy to remember, but what is sometimes hard to remember is that you have two options when scheduling a task. I often find myself picking the wrong one as it pops up in Intelli-sense and I forget there are 2 options.
- Run the task every X seconds/minutes/etc no matter what.
- Run the task every X seconds/minutes/etc *after* the previous task completed.
These two things can be very different. If you have a task that only takes a couple of seconds, it probably doesn’t matter much. But if you have a task that takes 2 minutes and you’re running it every 1 minute, then with option 1 you will always be running at least 2 copies of the task, whereas with option 2 you’ll just be running one copy at a time with a minute of buffer in between each task.
For both options, you can create the scheduled executor service the same way:
ScheduledExecutorService se = Executors.newSingleThreadScheduledExecutor();
But for option #1 (run every interval regardless of previous tasks), you would use this function:
se.scheduleAtFixedRate(this::refreshCache, 10, 120, TimeUnit.SECONDS);
And for option #2 (start counting after previous task completes), you would use this function.
se.scheduleWithFixedDelay(this::refreshCache, 10, 120, TimeUnit.SECONDS);