9

I need to run some code for a predefined length of time, when the time is up it needs to stop. Currently I am using a TimerTask to allow the code to execute for a set amount of time but this is causing endless threads to be created by the code and is just simply not efficient. Is there a better alternative?

Current code;

// Calculate the new lines to draw 
            Timer timer3 = new Timer();
            timer3.schedule(new TimerTask(){
                public void run(){
                    ArrayList<String> Coords = new ArrayList<String>();
                    int x = Float.valueOf(lastFour[0]).intValue();
                    int y = Float.valueOf(lastFour[1]).intValue();
                    int x1 = Float.valueOf(lastFour[2]).intValue();
                    int y1 = Float.valueOf(lastFour[3]).intValue();
                    //Could be the wrong way round (x1,y1,x,y)?
                    Coords = CoordFiller.coordFillCalc(x, y, x1, y1);
                    String newCoOrds = "";
                    for (int j = 0; j < Coords.size(); j++)
                    {
                        newCoOrds += Coords.get(j) + " ";
                    }
                    newCoOrds.trim();
                    ClientStorage.storeAmmendedMotion(newCoOrds);

                }

            }
            ,time);
skaffman
  • 398,947
  • 96
  • 818
  • 769
mhollander38
  • 775
  • 3
  • 11
  • 22

4 Answers4

17

If you are using Java5 or later, consider ScheduledThreadPoolExecutor and Future. With the former, you can schedule tasks to be run after a specified delay, or at specified intervals, thus it takes over the role of Timer, just more reliably.

The Timer facility manages the execution of deferred ("run this task in 100 ms") and periodic ("run this task every 10 ms") tasks. However, Timer has some drawbacks, and ScheduledThreadPoolExecutor should be thought of as its replacement. [...]

A Timer creates only a single thread for executing timer tasks. If a timer task takes too long to run, the timing accuracy of other TimerTasks can suffer. If a recurring TimerTask is scheduled to run every 10 ms and another TimerTask takes 40 ms to run, the recurring task either (depending on whether it was scheduled at fixed rate or fixed delay) gets called four times in rapid succession after the long-running task completes, or "misses" four invocations completely. Scheduled thread pools address this limitation by letting you provide multiple threads for executing deferred and periodic tasks.

Another problem with Timer is that it behaves poorly if a TimerTask throws an unchecked exception. The Timer thread doesn't catch the exception, so an unchecked exception thrown from a TimerTask terminates the timer thread. Timer also doesn't resurrect the thread in this situation; instead, it erroneously assumes the entire Timer was cancelled. In this case, TimerTasks that are already scheduled but not yet executed are never run, and new tasks cannot be scheduled.

From Java Concurrency in Practice, section 6.2.5.

And Futures can be constrained to run at most for the specified time (throwing a TimeoutException if it could not finish in time).

Update

If you don't like the above, you can make the task measure its own execution time, as below:

int totalTime = 50000; // in nanoseconds
long startTime = System.getNanoTime();
boolean toFinish = false;

while (!toFinish) 
{
    System.out.println("Task!");
    ...
    toFinish = (System.getNanoTime() - startTime >= totalTime);
}
Community
  • 1
  • 1
Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • 1
    Thanks, this looks helpful. What I need is for the code to be executed for a set period. ScheduledThreadPoolExecutor seems only able to use delays and waits, not perform a task for a period, similar with Future in waiting for an execution to complete. – mhollander38 Feb 09 '11 at 22:46
  • @mhollander38, my understanding is that if you call e.g. `Future.get(1, TimeUnit.SECOND)`, after one second it will throw a `TimeoutException` and the execution of the associated task will be terminated. I haven't verified it though. – Péter Török Feb 09 '11 at 22:56
  • @mhollander38, I added another solution, improving on the code in your (now deleted) repost. – Péter Török Feb 09 '11 at 23:30
  • have now implemented it and it is doing the trick. Thank you very much Péter. – mhollander38 Feb 10 '11 at 00:04
  • @Péter Török The timeout during the call to `Future.get(1, TimeUnit.SECOND)` has no influence on the underlying task at all. The "impatient caller" gets a `TimeoutException`, so it can do something else, but that's all. – maaartinus Jun 20 '12 at 10:35
4

[...] Currently I am using a TimerTask to allow the code to execute for a set amount of time [...]

The timer task will never stop the currently running task. In fact, it's only purpose is to restart the task over and over again.

There is no easy way of solving this without tight cooperation with the executing task. The best way is to let the task monitor it's own execution, and make sure that it returns (terminates) when its time is up.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • +1 despite the `Thread.stop()` reference, which should have `` tags around a giant warning that it is under no circumstances the correct approach to any problem from someone who needs to ask about Timer execution. If a task needs to run for a predetermined length of time, you need to tell the task that, and let it self-monitor as @aioobe suggests. – andersoj Feb 09 '11 at 22:26
0

If by stopping you mean the program has to exit, the solution is to create a thread for your processing and mark it as daemon, start it and in the main thread sleep for the time required, then simply return from the main() method.

Scratch that if by stopping, you mean just to stop the processing.

biziclop
  • 48,926
  • 12
  • 77
  • 104
0

It should also be noted that generally you only need to create one Timer(). From the code snippet I would guess you are creating multiple Timer() objects.

The time in the schedule method is the time to run at, not how long to run for.

Consider putting a start time before the for loop & putting a break in the for loop if you have exceeded the time limit.

long startedAt = System.currentTimeMillis();
long finishedCorrectly = true;
for (int j = 0; j < Coords.size(); j++) {
  newCoOrds += Coords.get(j) + " ";
  if ((System.currentTimeMillis() - startedAt) > MAX_TIME_TO_RUN) {
    finishedCorrectly = false;
    break;
  }
}
MrJacqes
  • 373
  • 1
  • 4