0

Let's say that I have an algorithm that does something for a given parameter. If the algorithm runs longer than 100 miliseconds then I want to stop it and try again for a different parameter.

I posted below the code that would test the algorithm for a random parameter... and how I think the code might look like:

public class StopThread {
    private Lock lock = new ReentrantLock();

    public static void main(String... args) {
        System.out.println("Starting threads...");
        (new StopThread()).startThreads(100);
    }

    private void startThreads(int nrOfThreads) {
        for (int i = 0; i < nrOfThreads; i++) {
            startThread(i, (long) (Math.random() * 10000000000l));
            System.out.println("Started thread number " + (i + 1));
        }
    }

    private void startThread(final int number, final long load) {
        Thread workerThread = new Thread() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    doAlgorithmWork(load);
                } finally {
                    System.out.println("Thread " + (number + 1) + " finished...");
                    lock.unlock();
                }
            }
        };
        Thread timerThread = new Thread() {
            @Override
            public void run() {
                try {
                    sleep(100);
                } catch (InterruptedException e) {
                }
            }
        };

        workerThread.start();
        timerThread.start();

        do {
            if (!workerThread.isAlive() || !timerThread.isAlive()) {
                workerThread.stop();
                timerThread.stop();
            }
        } while (!workerThread.isAlive() && !timerThread.isAlive());
    }

    protected void doAlgorithmWork(long load) {
        while (load-- > 0) {
        }
    }
}

I feel like this question should already have an answer, but what I found until now seemed complicated and I didn't know how to use it. I'm not that knowledgeable with threads and I would appreciate if you could post some code.

Adi
  • 321
  • 1
  • 17
  • 1
    Maybe helpful: http://stackoverflow.com/questions/2733356/killing-thread-after-some-specified-time-limit-in-java – Daniel Sep 25 '14 at 16:31
  • @Daniel I looked at the answer and from what I tried it doesn't work as expected. – Adi Sep 25 '14 at 18:21

1 Answers1

0

A very simple solution would look like this:

private void startThreads(int nrOfThreads) {
    for (int i = 0; i < nrOfThreads; i++) {
        Thread worker = new Thread() {
            @Override
            public void run() {
                doAlgorithmWork((long) (Math.random() * 10000000000l));
            }
        }
        worker.start();
        worker.join(100); //block until either the thread is done, or 100ms passed
        if (worker.isAlive()) worker.stop(); //if thread is still alive, stop it
    }
}

This will achieve your goal, but suffers from a number of "drawbacks"

  • It is single threaded (that is, all calls to doAlgorithm execute one after another, instead of in parallel, so you are only using a single core of your machine);
  • It uses the discouraged Thread.stop() method. A preferred approach is to instead have a "stop" flag which is set to true (in place of the stop() call), and which is also constantly checked for in doAlgorith;
  • It creates a new thread for each doAlgorithm call (instead of reusing a single thread), which is "wasteful", but for your case probably has little practical implications

UPDATE:

In order to avoid the deprecated stop() call, you will need to add a flag to your worker thread, creating a separate class like this:

public class Worker implements Runnable {
    private volatile boolean stopped = false;

    public void stop() {
        stopped = true;
    }

    @Override
    public void run() {
        doAlgorithmWork((long) (Math.random() * 10000000000l));
    }

    private void doAlgorithmWork(long load) {
        while (!stopped && load-- > 0) {
            //calculation
        }
    }
}

Then your runner looks like this:

private void startThreads(int nrOfThreads) {
    for (int i = 0; i < nrOfThreads; i++) {
        Thread worker = new Thread(new Worker());
        worker.start();
        worker.join(100); //block until either the thread is done, or 100ms passed
        if (worker.isAlive()) worker.stop(); //if thread is still alive, stop it
    }
}

You could also create a constructor for Worker which accepts the load value (instead of having it generated inside the Worker itself).

Note that if the calculation inside doAlgorithm() is too time-consuming, the thread may run for more than 100ms (since it always completes each calculation within the loop). If this is an issue, then your alternative is to interrupt the thread instead (calling worker.interrupt() will cause an InterruptedException to be thrown within the run() method).

xpa1492
  • 1,953
  • 1
  • 10
  • 19
  • Actually I want to queue the threads, and not run them in parallel or on multiple threads, since this is a benchmark for the algorithm. Thanks for the replay, it works how I want it to work. The drawback is like you mentioned using the deprecated `Thread.stop()`. – Adi Sep 26 '14 at 08:31
  • Further comments: I would like not to alter the `doAlgorithmWork()` method since I don't always have access to it. So still the first method seems the one to choose. Yet, even if it works, I don't feel I should trust `Thread.stop()`. It behaves strange. For example, after I call `Thread.stop()`, the finally block is sometimes executed and sometimes it isn't. And even if the threads finished executing, the program doesn't appear to terminate... – Adi Sep 29 '14 at 07:01
  • There is no way to handle this nicely, without modifying `doAlgorithmWork()`. You could try with 'Thread.interrupt()' (see http://stackoverflow.com/questions/3590000/what-does-java-lang-thread-interrupt-do for details), but it may still not be enough. – xpa1492 Sep 29 '14 at 08:18