Home > Blockchain >  How to find the result of first thread that finishes successfully in java?
How to find the result of first thread that finishes successfully in java?

Time:11-30

Suppose there are multiple threads trying to find a value, whichever thread finds it first should send the output to the main thread and all other threads should be terminated. Example -

public class WorkerThread implements Runnable {
    @Override
    public void run() {
        // some long task here, returns int value
    }
}

public class Main {
    public static void main(String[] args){
         // initialize multiple worker threads here
         // then get result from the thread that completes first
    }
}

I looked into docs and found invokeAny ExecutorService but this will return the result of any thread that has been completed successfully and not necessarily the first one.

CodePudding user response:

You can also use CountDownLatch and ExecutorService for achieving this.

Create CountDownLatch object with count = 1.

CountDownLatch latch = new CountDownLatch(1);

Use ExecutorService pool to execute the threads and pass the latch in all the threads.

workerThreadPool.execute(new WorkerThread(latch));

Wait for any thread to complete it's operation.

latch.await();

In the finally block of the thread run, shutdown the latch.

latch.countDown();

As soon as any thread countDown's the latch, the threadpool will stop all the other threads and shutdown.

workerThreadPool.shutdownNow();

The complete example would be below.

import static java.lang.Thread.sleep;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class WorkerThread implements Runnable
{

    CountDownLatch _latch;

    public WorkerThread(CountDownLatch latch)
    {
        _latch = latch;
    }

    @Override
    public void run()
    {
        try
        {
            // some long task here, returns int value
            System.out.println("In thread1 "   this.toString());
            sleep(5000);
        }
        catch (InterruptedException ex)
        {
            System.out.println("thread1 interupted");
        }
        finally
        {

            System.out.println("Finished1 "   this.toString());
            _latch.countDown();
        }
    }
}

class WorkerThread2 implements Runnable
{

    CountDownLatch _latch;

    public WorkerThread2(CountDownLatch latch)
    {
        _latch = latch;
    }

    @Override
    public void run()
    {
        try
        {
            // some long task here, returns int value
            System.out.println("In thread2 "   this.toString());
            sleep(10000);
        }
        catch (InterruptedException ex)
        {
            System.out.println("thread2 interupted");
        }
        finally
        {

            System.out.println("Finished2 "   this.toString());
            _latch.countDown();
        }
    }
}

public class Main
{

    public static void main(String[] args) throws InterruptedException
    {
        ExecutorService workerThreadPool = Executors.newFixedThreadPool(2);

        CountDownLatch latch = new CountDownLatch(1);

        workerThreadPool.execute(new WorkerThread(latch));
        workerThreadPool.execute(new WorkerThread2(latch));

        latch.await();

        workerThreadPool.shutdownNow();
    }
}

CodePudding user response:

You -could- pass a reference to the Thread where the Thread can send its results. But you'd better follow advice in the other answers and use a better API for this :)

public static void main(//) {

    ResultConsumer r = new ResultConsumer();
    ... create and start worker threads
}


public class WorkerThread implements Runnable {
    public WorkerThread ( ResultConsumer r ) {
         this.r=r
    }
     @Override
    public void run() {
        // some long task here, returns int value
        r.sendResult(....)
    }
}

CodePudding user response:

As @Andy Turner said, use a CompletionService:

    public static class WorkerThread implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            int nextInt = new Random().nextInt(10000);
            try {
                System.out.println("I will cost "   nextInt   " ms to finish job.--"   Thread.currentThread().getName());
                Thread.sleep(nextInt);
            } catch (InterruptedException ite) {
                System.out.println("I am interrupted.--"   Thread.currentThread().getName());
                return -1;
            }
            System.out.println("I am finish.--"   Thread.currentThread().getName());
            return nextInt;
        }
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        int nums = 3;
        ExecutorService executorService = Executors.newFixedThreadPool(nums);
        CompletionService<Integer> completionService = new ExecutorCompletionService<>(executorService);
        while (nums-- > 0) {
            completionService.submit(new WorkerThread());
        }
        Integer firstValue = completionService.take().get();
        System.out.println("FirstValue is "   firstValue);
        executorService.shutdownNow();
    }

And you can see in output, only one thread will complete the job (Because only call completionService#take once ), other threads will be interrupted and exit :

I will cost 8943 ms to finish job.--pool-1-thread-1
I will cost 9020 ms to finish job.--pool-1-thread-2
I will cost 5025 ms to finish job.--pool-1-thread-3
I am finish.--pool-1-thread-3
FirstValue is 5025
I am interrupted.--pool-1-thread-1
I am interrupted.--pool-1-thread-2
  • Related