1

I have this scala code, which works just fine (run() is overridden in class)

val processRunnable = new myProcessClassWithOverriddenRunFunction()
val processThread = new Thread(processRunnable)
processThread.start

What I want to do is set a timeout for processThread thread. How can I do that?

I did some research and couldn't find any parameter we can pass to new Thread() or any function in processThread to achieve that.

Found some solutions on stackoveflow which implemented a ExecutorService but unfortunately, that is not implementable in this particular problem as making another new ExecutorService for just a single processThread, everytime this function is called seems inefficient. There are some other reasons as well but my question is how can I implement that functionality on this code?

saadi
  • 646
  • 6
  • 29
  • You need to implement it in your thread yourself, so that it exits after reaching a certain run time. – rustyx Nov 05 '18 at 12:12
  • @rustyx I don't understand, can you elaborate a little? Won't I need another thread to work as a timer? Where can I put a check for that timer? – saadi Nov 05 '18 at 12:16
  • Why are you writing java code in scala syntax? That seems ... counterproductive. – Dima Nov 05 '18 at 12:24

2 Answers2

3

There is no way to achieve that without the thread cooperating. This is similar in nature to how to make a thread interruptible, and has to do with the fact that it is in general unsafe to stop running threads asynchronously (and a timeout is asynchronous).

Your thread needs to include the timeout capability as part of it's implementation, so that it can act on a timeout condition when it is safe for it to do so.

For example:

public class MyProcessClass {
    private final long timeoutMillis = 30000;
    public void run() {
        long timeout = System.currentTimeMillis() + timeoutMillis;
        while (System.currentTimeMillis() < timeout) {
            // Process next chunk of work
        }
    }
}

PS. Don't be misled by the other answer based on the ExecutorService - it requires the thread to be interruptible, i.e. the same solution as shown above.

        while (!Thread.interrupted()) {
            // Process next chunk of work
        }
rustyx
  • 80,671
  • 25
  • 200
  • 267
  • If we rely on the `Thread.interrupted()` we may get into trouble in case we want graceful shutdown and to finish the currently executing task. In that case `PoisonPill` is a better choice. – St.Antario Nov 07 '18 at 08:38
1

In Java, you can use

CompletableFuture<Void> future = CompletableFuture.runAsync(processRunnable);
future.get(1000, TimeUnit.MILLISECONDS);

To future.get function will throw a TimeOutException when timeout (1 second in the example above) is reached and the timeout case can be handled in catch block.
Complete code will be something like this:

try {
     CompletableFuture<Void> future = CompletableFuture.runAsync(processRunnable);
    future.get(1000, TimeUnit.MILLISECONDS);
}
catch{
case texc : TimeoutException => println("Timeout is reached.")
case exc  : Exception => println(exc.getmessage)
}
saadi
  • 646
  • 6
  • 29
daniu
  • 14,137
  • 4
  • 32
  • 53
  • Hi @danju! thanks but I have some questions, there is no `future.getOrElse` function, where does control go if future fails? If I want to do something if future fails, where and how can I do it? – saadi Nov 05 '18 at 12:13
  • 1
    @saadi in that case, `future.get()` will throw an Exception (a `TimeoutException` if the timeout was reached, or an `ExecutionException` wrapping the underlying exception if the `run()` method threw an exception) – OhleC Nov 05 '18 at 12:19
  • 1
    note that while the CompletableFuture will return after the timeout, the actual thread may still continue to run and use resources. @rustyx answer is better in this regard. – cello Nov 06 '18 at 08:15