Executors: How to synchronously wait until all tasks have finished if tasks are created recursively?

前端 未结 9 1509
傲寒
傲寒 2020-12-31 09:37

My question is strongly related to this one here. As was posted there, I would like the main thread to wait until the work queue is empty and all tasks have finished. The pr

9条回答
  •  别那么骄傲
    2020-12-31 09:55

    Java 7 provides a synchronizer that fits this use case called Phaser. It's a re-usable hybrid of a CountDownLatch and CyclicBarrier that can both increase and decrease the number of registered parties (similar to an incrementable CountDownLatch).

    The basic pattern to using the phaser in this scenario is to register tasks with the phaser when created and arrive when completed. When the number of arrived parties matches the number of registered, the phaser "advances" to the next phase, notifying any waiting threads of the advance when it takes place.

    Here's an example I've created of waiting for recursive task completion. It naively finds the first few numbers of the Fibonacci sequence for demonstration purposes:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ForkJoinPool;
    import java.util.concurrent.Phaser;
    import java.util.concurrent.atomic.AtomicLong;
    
    /**
     * An example of using a Phaser to wait for the completion of recursive tasks.
     * @author Voxelot
     */
    public class PhaserExample {
        /** Workstealing threadpool with reduced queue contention. */
        private static ForkJoinPool executors;
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) throws InterruptedException {
            executors = new ForkJoinPool();
            List sequence = new ArrayList<>();
            for (int i = 0; i < 20; i++) {
                sequence.add(fib(i));
            }
            System.out.println(sequence);
        }
    
        /**
         * Computes the nth Fibonacci number in the Fibonacci sequence.
         * @param n The index of the Fibonacci number to compute
         * @return The computed Fibonacci number
         */
        private static Long fib(int n) throws InterruptedException {
            AtomicLong result = new AtomicLong();
            //Flexible sychronization barrier
            Phaser phaser = new Phaser();
            //Base task
            Task initialTask = new Task(n, result, phaser);
            //Register fib(n) calling thread
            phaser.register();
            //Submit base task
            executors.submit(initialTask);
            //Make the calling thread arrive at the synchronization
            //barrier and wait for all future tasks to arrive.
            phaser.arriveAndAwaitAdvance();
            //Get the result of the parallel computation.
            return result.get();
        }
    
        private static class Task implements Runnable {
            /** The Fibonacci sequence index of this task. */
            private final int index;
            /** The shared result of the computation. */
            private final AtomicLong result;
            /** The synchronizer. */
            private final Phaser phaser;
    
            public Task(int n, AtomicLong result, Phaser phaser) {
                index = n;
                this.result = result;
                this.phaser = phaser;
                //Inform synchronizer of additional work to complete.
                phaser.register();
            }
    
            @Override
            public void run() {
                if (index == 1) {
                    result.incrementAndGet();
                } else if (index > 1) {
                    //recurrence relation: Fn = Fn-1 + Fn-2
                    Task task1 = new Task(index - 1, result, phaser);
                    Task task2 = new Task(index - 2, result, phaser);
                    executors.submit(task1);
                    executors.submit(task2);
                }
                //Notify synchronizer of task completion.
                phaser.arrive();
            }
        }
    }
    

提交回复
热议问题