0

How to run the thread for the specific amount of time and return some result when time elapse?

The best solution I can think so far is to measure time manually. But maybe there is more elegant, out of the box solution? 

I have an algorithm that in each iteration improves previous solution. I'd like to run this code in a separate thread for the predefined amount of time. When the time elapse, the best (the latest) solution should be returned.

Since I want to return the solution, I can't just use Future#get(long timeout, TimeUnit unit) - it would result in TimeoutException. The same about interrupting thread after some time from the "controlling" thread - in such case, Future would be cancelled and returned null.

My current solution is as follows:

The timer logic:

private class ExecutionTimer {

    private final long executionTimeLimit;

    private long startTime;

    // accepts execution time limit in _miliseconds_
    public ExecutionTimer(final int executionTimeLimit) {
        this.executionTimeLimit = TimeUnit.MILLISECONDS.toNanos(executionTimeLimit);
    }

    public void start() {
        this.startTime = System.nanoTime();
    }

    public boolean hasElapsed() {
        return (System.nanoTime() - startTime) >= executionTimeLimit;
    }
}

...and the worker thread:

 private class WorkerThread implements Callable<Double> {

        private final ExecutionTimer executionTimer;

        public WorkerThread(final int executionTimeLimit) {
            this.executionTimer = new ExecutionTimer(executionTimeLimit);
        }

        @Override
        public Double call() throws Exception {
            executionTimer.start();

            double partialSolution = 0;
            while (!executionTimer.hasElapsed()) {
                // let's imagine that here solution is improved ;)
                partialSolution = new Random().nextDouble(); 
            }
            return partialSolution;
        }
    }

EDIT: The worker thread can work indefinitely without interrupting it from outside - it is fine because algorithm can always improve previous solution (of course after some significant amount of time improvements are relatively small)

omnomnom
  • 8,911
  • 4
  • 41
  • 50

4 Answers4

2

You could store the intermediate results in a shared thread safe variable (for example volatile double in your case) - when your future times out, you can retrieve the latest calculated value from that variable.

In other words:

  • if future.get(...) returns a value, use it
  • if you get a TimeoutException, retrieve the value by calling yourWorkerThread.getLatestValue();, which returns a volatile double latestValue which is updated at every loop, instead of your local partialSolution.

Alternatively, this post points to the Guava library and other solution (that all come down to the 2 options discussed in my comment). Note that Guava, internally, uses a future with timeout.

Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783
  • I though about it, but manually-timing solution seems more elegant IMHO - especially because of this exception condition. Actually I will always get TimeoutException - worker thread can work indefinitely - it can always improve previous solution. – omnomnom Aug 18 '12 at 18:15
  • @PiotrekDe That is a subjective view which I can't argue with! You only have 2 ways really: either (1) your task doesn't know about how much time it's got (which I think is better: [single responsibility principle](http://en.wikipedia.org/wiki/Single_responsibility_principle), etc.) and your calling code interrupts it when it thinks enough time has elapsed - or (2) you make your task aware of the time it is spending doing its stuff, and your solution is fine. – assylias Aug 18 '12 at 18:26
  • @PiotrekDe Added a link in my answer. – assylias Aug 18 '12 at 18:33
1

I would suggest a Producer-Consumer pattern:

The algorithm that is responsible for the cultivation of the result is constantly producing new and better results and puts them into a shared thread safe resource.

The client who is interested in this result consumes this resource each predefined interval, set to the timeout in your question.

The resource itself could be a stream (e.g. BlockingQueue) or a single variable.

This has the advantages that it is very easy to reason about, it defines clear boundaries and is very flexible. For example: the client can block as long as there is no result at all, or it can block as long as there is no new and improved result. All variations on the producer consumer pattern, just tweak the producers notification condition.

Vitaliy
  • 8,044
  • 7
  • 38
  • 66
1

Consider using Timer & TimerTask

import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

public class Solver implements Callable<Double> {

    private final AtomicBoolean running = new AtomicBoolean(true);

    public void stop() {
        this.running.set(true);
    }

    @Override
    public Double call() throws Exception {
        Double answer = null;
        while (this.running.get()) {
            answer = keepImproving();
        }
        // TODO Auto-generated method stub
        return answer;
    }

}

class Schedular extends TimerTask {

    private final Solver solver;

    public Schedular(Solver solver) {
        this.solver = solver;
    }

    @Override
    public void run() {
        this.solver.stop();
    }

}

Use something like below

final Solver solver = new Solver();
Schedular schedular = new Schedular(solver);
final Timer timer = new Timer();
timer.schedule(schedular, 0, TimeUnit.MINUTES.toMillis(1));

ExecutorService executor = // get a executor somehow
final Future<Double> future = executor.submit(solver);
final Double answer = future.get();
System.out.println(answer);

The idea is to use Timer & TimerTask to trigger the stop signal so that algorithm stop improving the answer.

Kowser
  • 8,123
  • 7
  • 40
  • 63
  • Finally, I've implemented the code with solution proposed in my question. However, if I had to chose another one I'd use this, proposed by Kowser. All answers are fine, however, taking into consideration all of them, this one is the most elegant in my opinion. Of course this is subjective view, but I have to choose one answer somehow. – omnomnom Sep 07 '12 at 06:49
0

You can use the normal Future.get(), it waits indefinately.

Biro456
  • 61
  • 1
  • 3
  • but I don't want to wait indefinitely – omnomnom Aug 18 '12 at 17:59
  • As thread running the algorithm is keeping note of its time you can be sure that it will stop running when the time elapses. That way the other thread that is apparently waiting forever now has a real limit to when it will get the result. – Biro456 Aug 18 '12 at 18:12
  • Of course I can use Future#get and I'll do it if my 'worker thread' (running algorithm) is aware of time elapsed (as is is done in the code snippet in my question). But this is the logic I'd like to avoid - measuring time manually by System.nanoTime() instead of using some built-in JDK solution (if it exists...) – omnomnom Aug 18 '12 at 18:25
  • Hmn... I couldn't find any such solution... I think the JDK built-in is the System.nanoTime itself. I believe that your solution is good enough, because it serves its purpose perfectly. It's also probable that someone somewhere has already implemented your timing code, but that happens a lot. The Apache Project may have something. Try not to overengineer the code because it always ends up on bad legibility. – Biro456 Aug 18 '12 at 18:38