Home > database >  How to stop all threads as soon as one is finished?
How to stop all threads as soon as one is finished?

Time:11-10

I have 5 threads (5 instances of one Runnable class) starting approximately at the same time (using CyclicBarrier) and I need to stop them all as soon as one of them finished.

Currently, I have a static volatile boolean field threadsOver that I'm setting to true at the end of doSomething(), the method that run() is calling.

private static final CyclicBarrier barrier = new CyclicBarrier(5);
private static volatile boolean threadsOver;
@Override
public void run() {
    try {
        /* waiting for all threads to have been initialised,
           so as to start them at the same time */
        barrier.await();
        doSomething();
    } catch (InterruptedException | BrokenBarrierException e) {
        e.printStackTrace();
    }
}
public void doSomething() {
    // while something AND if the threads are not over yet
    while (someCondition && !threadsOver) {
         // some lines of code
    }
    // if the threads are not over yet, it means I'm the first one to finish
    if (!threadsOver) {
         // so I'm telling the other threads to stop
         threadsOver = true;
    }
}

The problem with that code is that the code in doSomething() is executing too fast and as a result, the threads that finish after the first one are already over by the time that the first thread noticed them.

I tried adding some delay in doSomething() using Thread.sleep(), which reduced the number of threads which finished even after the first one, but there are still some times where 2 or 3 threads will finish execution completely.

How could I make sure that when one thread is finished, all of the others don't execute all the way to the end?

CodePudding user response:

First where I copied code snippets from: https://www.baeldung.com/java-executor-service-tutorial .

As you have 5 tasks of which every one can produce the result, I prefer Callable, but Runnable with a side effect is handled likewise.

The almost simultaneous start, the Future task aspect, and picking the first result can be done by invokeAny below:

Callable<Integer> callable1 = () -> {
    return 1*2*3*5*7/5;
};

List<Callable<Integer>> callables = List.of(callable1, callable2, ...);

ExecutorService executorService = new ThreadPoolExecutor(5);

Integer results = executorService.invokeAny(callables);
executorService.shutDown();

invokeAny() assigns a collection of tasks to an ExecutorService, causing each to run, and returns the result of a successful execution of one task (if there was a successful execution).

CodePudding user response:

You can add synchronized to your method. This will make doSomething() accessible by only one thread at the time, and then when you reassign boolean value and the other thread steps into the doSomething(), it will not execute the given block.

  • Related