Wait until any of Future is done

前端 未结 8 1080
长发绾君心
长发绾君心 2021-02-01 01:09

I have few asynchronous tasks running and I need to wait until at least one of them is finished (in the future probably I\'ll need to wait util M out of N tasks are finished). C

相关标签:
8条回答
  • 2021-02-01 01:14

    See this option:

    public class WaitForAnyRedux {
    
    private static final int POOL_SIZE = 10;
    
    public static <T> T waitForAny(Collection<T> collection) throws InterruptedException, ExecutionException {
    
        List<Callable<T>> callables = new ArrayList<Callable<T>>();
        for (final T t : collection) {
            Callable<T> callable = Executors.callable(new Thread() {
    
                @Override
                public void run() {
                    synchronized (t) {
                        try {
                            t.wait();
                        } catch (InterruptedException e) {
                        }
                    }
                }
            }, t);
            callables.add(callable);
        }
    
        BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(POOL_SIZE);
        ExecutorService executorService = new ThreadPoolExecutor(POOL_SIZE, POOL_SIZE, 0, TimeUnit.SECONDS, queue);
        return executorService.invokeAny(callables);
    }
    
    static public void main(String[] args) throws InterruptedException, ExecutionException {
    
        final List<Integer> integers = new ArrayList<Integer>();
        for (int i = 0; i < POOL_SIZE; i++) {
            integers.add(i);
        }
    
        (new Thread() {
            public void run() {
                Integer notified = null;
                try {
                    notified = waitForAny(integers);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                System.out.println("notified=" + notified);
            }
    
        }).start();
    
    
        synchronized (integers) {
            integers.wait(3000);
        }
    
    
        Integer randomInt = integers.get((new Random()).nextInt(POOL_SIZE));
        System.out.println("Waking up " + randomInt);
        synchronized (randomInt) {
            randomInt.notify();
        }
      }
    }
    
    0 讨论(0)
  • 2021-02-01 01:18

    As far as I know, Java has no analogous structure to the WaitHandle.WaitAny method.

    It seems to me that this could be achieved through a "WaitableFuture" decorator:

    public WaitableFuture<T>
        extends Future<T>
    {
        private CountDownLatch countDownLatch;
    
        WaitableFuture(CountDownLatch countDownLatch)
        {
            super();
    
            this.countDownLatch = countDownLatch;
        }
    
        void doTask()
        {
            super.doTask();
    
            this.countDownLatch.countDown();
        }
    }
    

    Though this would only work if it can be inserted before the execution code, since otherwise the execution code would not have the new doTask() method. But I really see no way of doing this without polling if you cannot somehow gain control of the Future object before execution.

    Or if the future always runs in its own thread, and you can somehow get that thread. Then you could spawn a new thread to join each other thread, then handle the waiting mechanism after the join returns... This would be really ugly and would induce a lot of overhead though. And if some Future objects don't finish, you could have a lot of blocked threads depending on dead threads. If you're not careful, this could leak memory and system resources.

    /**
     * Extremely ugly way of implementing WaitHandle.WaitAny for Thread.Join().
     */
    public static joinAny(Collection<Thread> threads, int numberToWaitFor)
    {
        CountDownLatch countDownLatch = new CountDownLatch(numberToWaitFor);
    
        foreach(Thread thread in threads)
        {
            (new Thread(new JoinThreadHelper(thread, countDownLatch))).start();
        }
    
        countDownLatch.await();
    }
    
    class JoinThreadHelper
        implements Runnable
    {
        Thread thread;
        CountDownLatch countDownLatch;
    
        JoinThreadHelper(Thread thread, CountDownLatch countDownLatch)
        {
            this.thread = thread;
            this.countDownLatch = countDownLatch;
        }
    
        void run()
        {
            this.thread.join();
            this.countDownLatch.countDown();
        }
    }
    
    0 讨论(0)
  • 2021-02-01 01:29

    simple, check out ExecutorCompletionService.

    0 讨论(0)
  • 2021-02-01 01:29

    ExecutorService.invokeAny

    0 讨论(0)
  • 2021-02-01 01:31

    Since you don't care which one finishes, why not just have a single WaitHandle for all threads and wait on that? Whichever one finishes first can set the handle.

    0 讨论(0)
  • 2021-02-01 01:33

    If you can use CompletableFutures instead then there is CompletableFuture.anyOf that does what you want, just call join on the result:

    CompletableFuture.anyOf(futures).join()
    

    You can use CompletableFutures with executors by calling the CompletableFuture.supplyAsync or runAsync methods.

    0 讨论(0)
提交回复
热议问题