Thursday, January 15, 2009

Watch out for long running tasks with Java Timer

The problem? Write a code which will execute every N seconds.

The solution? Using a Timer with scheduleAtFixedRate.

Now you got two problems :-), unless you've carefully read the documentation which states (emphasis added):

If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up."

You might not want this, especially if the backlog is long... The solution is given by the TimerTask documentation:

  if (System.currentTimeMillis() - scheduledExecutionTime() >= MAX_TARDINESS)
    return;  // Too late; skip this execution.

PS. My first instinct was to use the "resubscribe from the inner function" pattern, which is very popular in the Javascript world. For some reason very few people seem to know about the setInterval function... Getting back to the topic: apparently calling schedule from inside the run function results in an IllegalStateException being thrown, although I couldn't find the documentation stating this or giving a reason...

Update: as it was pointed out by a colleague, you can solve the problem with the schedule call. The upside is that you have minimal code change, the downside being that you will have two short-scheduled events if one execution takes long, because it uses the start time for the previous execution to calculate the execution time for the next event (the scenario is: the task starts at T and takes until T+t1 to execute. The next scheduled execution will be at T+t2, and if t2 < t1, it will be re-executed shortly after the first execution. This is not a problem, unless your scheduled task routinely takes longer than the rate to execute).

No comments:

Post a Comment