views:

781

answers:

8

I want to run a thread for some fixed amount of time. If it is not completed within that time, I want to either kill it, throw some exception, or handle it in some way. How can it be done?

One way of doing it as I figured out from this thread is to use a TimerTask inside the run() method of the Thread.

Are there any better solutions for this?

 
EDIT: Adding a bounty as I needed a clearer answer. The ExecutorService code given below does not address my problem. Why should I sleep() after executing (some code - I have no handle over this piece of code)? If the code is completed and the sleep() is interrupted, how can that be a timeOut?

The task that needs to be executed is not in my control. It can be any piece of code. The problem is this piece of code might run into an infinite loop. I don't want that to happen. So, I just want to run that task in a separate thread. The parent thread has to wait till that thread finishes and needs to know the status of the task (i.e whether it timed out or some exception occured or if its a success). If the task goes into an infinite loop, my parent thread keeps on waiting indefinitely, which is not an ideal situation.

+7  A: 

Consider using an instance of ExecutorService. Both invokeAll() and invokeAny() methods are available with a timeout parameter.

The current thread will block until the method completes (not sure if this is desirable) either because the task(s) completed normally or the timeout was reached. You can inspect the returned Future(s) to determine what happened.

Drew Wills
+17  A: 
erickson
+9  A: 

Indeed rather use ExecutorService instead of Timer, here's an SSCCE

package com.stackoverflow.q2275443;

import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Test {

    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.invokeAll(Arrays.asList(new Task()), 2, TimeUnit.SECONDS);
        executor.shutdown();
    }

}

class Task implements Callable<String> {
    public String call() throws Exception {
        try {
            System.out.println("Started..");
            Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
            System.out.println("Finished!");
        } catch (InterruptedException e) {
            System.out.println("Terminated!");
        }
        return null;
    }
}

Play a bit with the timeout argument in invokeAll() method, e.g. increase it to 5 and you'll see that the thread finishes. You can intercept thread interruption in the catch (InterruptedException e) block.

Update: to clarify a conceptual misunderstanding, the sleep() is not required. It is just used for SSCCE/demonstration purposes. Just do your long running task right there in place of sleep().

BalusC
+1 for the SSCCE (1st time i see this website)
chburd
A: 

I think the answer mainly depends on the task itself.

  • Is it doing one task over and over again?
  • Is it necessary that the timeout interrupts a currently running task immediately after it expires?

If the first answer is yes and the second is no, you could keep it as simple as this:

public class Main {

    private static final class TimeoutTask extends Thread {
        private final long _timeoutMs;
        private Runnable _runnable;

        private TimeoutTask(long timeoutMs, Runnable runnable) {
            _timeoutMs = timeoutMs;
            _runnable = runnable;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() < (start + _timeoutMs)) {
                _runnable.run();
            }
            System.out.println("execution took " + (System.currentTimeMillis() - start) +" ms");
        }

    }

    public static void main(String[] args) throws Exception {
        new TimeoutTask(2000L, new Runnable() {

            @Override
            public void run() {
                System.out.println("doing something ...");
                try {
                    // pretend it's taking somewhat longer than it really does
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
}

If this isn't an option, please narrow your requirements - or show some code.

sfussenegger
+1  A: 

I think you should take a look at proper concurrency handling mechanisms (threads running into infinite loops doesn't sound good per se, btw). Make sure you read a little about the "killing" or "stopping" Threads topic.

What you are describing,sound very much like a "rendezvous", so you may want to take a look at the CyclicBarrier.

There may be other constructs (like using CountDownLatch for example) that can resolve your problem (one thread waiting with a timeout for the latch, the other should count down the latch if it has done it's work, which would release your first thread either after a timeout or when the latch countdown is invoked).

I usually recommend two books in this area: Concurrent Programming in Java and Java Concurrency in Practice.

Dieter
A: 
elou
piece, brother :)
Russell
;-)---------------
elou
A: 

One thing that I've not seen mentioned is that killing threads is generally a Bad Idea. There are techniques for making threaded methods cleanly abortable, but that's different to just killing a thread after a timeout.

The risk with what you're suggesting is that you don't what state the thread will be in when you kill it - so you risk introducing instability. A better solution is to make sure your threaded code either doesn't hang itself, or will respond nicely to an abort request.

Dan Puzey
A: 

The following snippet will start an operation in a separate thread, then wait for up to 10 seconds for the operation to complete. If the operation does not complete in time, the code will attempt to cancel the operation, then continue on its merry way. Even if the operation cannot be cancelled easily, the parent thread will not wait for the child thread to terminate.

ExecutorService executorService = getExecutorService();
Future<SomeClass> future = executorService.submit(new Callable<SomeClass>() {
    public SomeClass call() {
        // Perform long-running task, return result. The code should check
        // interrupt status regularly, to facilitate cancellation.
    }
});
try {
    // Real life code should define the timeout as a constant or
    // retrieve it from configuration
    SomeClass result = future.get(10, TimeUnit.SECONDS);
    // Do something with the result
} catch (TimeoutException e) {
    future.cancel(true);
    // Perform other error handling, e.g. logging, throwing an exception
}

The getExecutorService() method can be implemented in a number of ways. If you do not have any particular requirements, you can simply call Executors.newCachedThreadPool() for thread pooling with no upper limit on the number of threads.

markusk