0

I want to have 3 threads running in parallel and return the results in parallel, so that when a task returns true when it has generated the right number, all the other threads stop executing.

I have tried using a CallableFuture and Callable with a newFixedThreadPool, but I seem to get the desired result. The problem each time is that I have to wait for all the results to be completed, yet I simply want to stop all threads if one thread has found the random number I am looking for.

Here is the following pseudocode:

    public class GenerateRandomIntegerTask implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        // From constructor
        int rand1 = rand1;
        int rand2 = rand2;


        // Do the work here
        Rand rand = new Random();
        int rand3 = random.nextInt(100);

        if(rand1 + rand2 + rand3 == 5)
        {
            // STOP ALL TRHREADS
            return true;
        }
        else
        {
            return false;
        }
    }
 }

I execute this using a newFixedThreadPool like so:

        MultiValuedMap<Integer, Integer> randMap = randHelper.retrieveRandMap();

        Iterator it = randMap.entries().iterator();

        ExecutorService executor = Executors.newFixedThreadPool(3);

        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry)it.next();
            int rand1 = pair.getKey().toString();
            String rand2 = pair.getValue().toString();

            executor.submit(new GenerateRandomIntegerTask (rand1, rand2));
        }

Does anybody know how to achieve this?

And before you mark it as duplicate, please take some time to consider whether it really is because I haven't seen other questions describing this exact same problem.

Mihael Keehl
  • 335
  • 5
  • 16
  • *"And before you mark it as duplicate"* ;) – akuzminykh Jul 08 '20 at 17:53
  • @akuzminykh That wink at the end insinuates you did but I really don't get why, I have read countless of threads but I can't figure it out... – Mihael Keehl Jul 08 '20 at 17:56
  • 1
    You could use a flag to signal that a thread is supposed to stop. The thread can check it periodically and stop itself in a controlled way by returning. The thread that returns `true` first sets the flag. – akuzminykh Jul 08 '20 at 17:59
  • `CompletableFuture` should work wonderfully for this, what went wrong? [CompletableFuture#anyOf](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#anyOf-java.util.concurrent.CompletableFuture...-) sounds exactly like what you're wanting. – Rogue Jul 08 '20 at 18:02
  • @akuzminykh Thank you! I haven't thought of that, I'm thinking right now how I should put that into words/code... Should I then create a shared object and supply it to each thread? The problem maybe is that I then have to check after each (task work) statement if the object property, e.g. hasFinished is set to true but that seems a bit ugly to put after each line. Good idea though. – Mihael Keehl Jul 08 '20 at 18:05
  • @Rogue That "returns" the first that is completed, not the one that completes with `true`. – akuzminykh Jul 08 '20 at 18:05
  • 1
    @MihaelKeehl You have many options to do that signal, e.g. `volatile boolean` or `AtomicBoolean`. You could even use a seperate `CompletableFuture` and make the first finished thread `complete` it with the result. All threads check it `isCompleted` periodically. No, you don't check it after each statement. You do checks when the data would be left in a consistent state if the thread would return there. – akuzminykh Jul 08 '20 at 18:10
  • @Rogue The problem with the CallableFuture was that I still have to call 'result.get' after using 'cb.thenApply(...)' and that doesn't run in parallel but that was done using 'supplyAsync' instead. I could take a look at 'anyOf' though. But like akuzminykh suggested that will also just return a single result it seems. Only one action should be fire based on the result afterwards, that will not work if I get a single result. – Mihael Keehl Jul 08 '20 at 18:12
  • 1
    I've written an answer here to a question that is somewhat related: [Interrupt all threads if an exception occurs in any](https://stackoverflow.com/questions/62646788/interrupt-all-threads-if-an-exception-occurs-in-any/62647874#62647874) Maybe it helps you a bit. – akuzminykh Jul 08 '20 at 18:12
  • @akuzminykh Thank you, that question is indeed similar in nature. I will try to apply that concept to my own code. – Mihael Keehl Jul 08 '20 at 18:17

1 Answers1

1

@mihael Keehl, I think what you need to use is a "CountDownLatch" which will act as a gate to make sure configured number of threads ( initializable using its constructor ) will complete their execution before control passes to the next line of code in the main thread. After the latch is released, you will be able to inspect the state of threads and interrupt the ones still running. Please let me know if you need specific code examples - i can help.