8

I have n threads running in parallel and each of them does some custom logic. However, my requirement is that when any of the threads finishes it execution, all other threads should stop execution and return.

What is the best way to implement this ? I thought of doing this by having a shared boolean variable. When any of the threads finishes it execution, it will set the boolean. All all the threads periodically read this variable and exit if when it is set.

Also, my custom logic is an infinite loop and as soon as i know some other thread has finished execution I want to stop execution after the current iteration.

What is the proper way of doing this ?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
shadowfax
  • 971
  • 1
  • 10
  • 17
  • possible duplicate of [inter thread communication in java](http://stackoverflow.com/questions/2170520/inter-thread-communication-in-java) – Anders R. Bystrup Jun 18 '13 at 10:46
  • Spawn all other threads from that special thread !!!! – AllTooSir Jun 18 '13 at 10:46
  • @AndersR.Bystrup I'm not convinced that's a great duplicate, it doesn't really answer this question. – Duncan Jones Jun 18 '13 at 10:47
  • Every time you create new instance of thread, add this thread to global List of threads. This list of threads will be acting as thread pool. If one thread stops execution. You loop the pool and stop each thread. This is pretty simple solution, hope this will help you. – ilya.stmn Jun 18 '13 at 11:01
  • possible duplicate of [communication between threads in java: stopping a thread if another thread has finished](http://stackoverflow.com/questions/2816005/communication-between-threads-in-java-stopping-a-thread-if-another-thread-has-f) – Raedwald Jun 18 '13 at 11:41
  • What exactly are you doing in those `Thread`s, why aren't they waiting on something? Is it a mathematical calculation, e.g. finding a prime? – gaborsch Jun 18 '13 at 12:26

3 Answers3

9

Use an ExecutorService and its .invokeAny() method (note: there is also a version with a timeout).

From the Javadoc:

Executes the given tasks, returning the result of one that has completed successfully (i.e., without throwing an exception), if any do.

One you have your result, .shutdown() the executor.

See the Executors class to obtain an executor which fits your needs.

Another solution is the ExecutorCompletionService class; in this Case you'd .take() instead of .invokeAny(), and would have to submit each task one by one. And you'd also have to keep a reference to your ExecutorService since you need one as an argument, and need to shut it down as well.

(note: if you don't return a result, make Callable<Void> instances)

fge
  • 119,121
  • 33
  • 254
  • 329
  • Thanks fge. ExecutorCompletionService will rely on Future.Cancel and it will interrupt only if the thread is waiting on something. Now in my use case, i have an infinite loop and want to stop executing as soon as the current iteration is done. In my use case, it is not good if the iterations take place even after cancel. – shadowfax Jun 18 '13 at 11:13
  • What do you mean by "rely on interrupt"? – fge Jun 18 '13 at 11:37
  • @shadowfax see comment above (I don't know if you saw it), I don't understand your question. – fge Jun 18 '13 at 11:47
1

I would prefer to use a common semaphore to control the execution, and have a frequent check in the threads.

public class MyTask implements Runnable {
    private static volatile boolean isDone = false
    @Override
    public void run() {
        while(true) {
            if (isDone) {
                break;
            }

            // do some calculation, no wait() s

            if (...has result...) {
                isDone = true;
                break;
            }
        }
    }
}

Thread t1 = new Thread(new MyTask());
Thread t2 = new Thread(new MyTask());
Thread t3 = new Thread(new MyTask());
t1.start();
t2.start();
t3.start();

The only thing you must be aware of is the static volatile boolean variable. Static because the same flag must be accessed by all threads, volatile to prevent the JVM to cache its data. If you don't mark it as volatile, the compiler may produce such a bytecode that it would optimize the read from a field such a way that it reads the field only once, and uses the saved value for every loop execution.

If your tasks are different and you implement different loops, you can use any external public static volatile boolean field to hold the flag.

This solution does not depend on the wait state of the thread. You can check isDone multiple places in your loop (even before every block of code). If you guarantee that your code will reach an exit check, there is no need to interrupt the threads anyway.

gaborsch
  • 15,408
  • 6
  • 37
  • 48
0

Look, you can keep on a shared global array all the Thread objects, then at the end of each task you can perform a call to a "cleanup" function that just takes all these objects and performs a call to "interrupt" on them. That would cause the first thread to finish to finish the execution of the rest.

public class MyMain
{
   public static Thread workers[NUM_WORK];
   public static void main(..)
   {
      MyMain.workers[0] = new Thread(new MyTask0());
      .
      .
      .
      MyMain.workers[n] = new Thread(new MyTaskN());
      //Then start them all..
      // And wait for them unless you want them to die before execution ;)
   }
}

Then on your other workers

import MyMain;
public class MyTaskI implements Runnable
{
   public void run()
   {
      //Do all the work
      for(Thread t : MyMain.workers)
      {
         // If it is not this thread
         t.interrupt();
      }
   }
}

Sorry if I made any syntax errors. It's been a while since I did Java, the idea is that you get the point ;)

cgledezma
  • 612
  • 6
  • 11
  • As the OP mentioned, `thread.interrupt()` relies on `wait` state. If the thread is **not waiting** on anything, this solution will not work. – gaborsch Jun 18 '13 at 13:48
  • Then you can do a minimal timed wait at the beginning of each iteration. If there is not much work to be done on each loop, then the time delay shouldn't be a problem. – cgledezma Jun 18 '13 at 13:56