wait until all threads finish their work in java

后端 未结 16 1884
情深已故
情深已故 2020-11-22 14:10

I\'m writing an application that has 5 threads that get some information from web simultaneously and fill 5 different fields in a buffer class.
I need to validate buffer

相关标签:
16条回答
  • 2020-11-22 14:53

    Store the Thread-objects into some collection (like a List or a Set), then loop through the collection once the threads are started and call join() on the Threads.

    0 讨论(0)
  • 2020-11-22 14:54

    You can join to the threads. The join blocks until the thread completes.

    for (Thread thread : threads) {
        thread.join();
    }
    

    Note that join throws an InterruptedException. You'll have to decide what to do if that happens (e.g. try to cancel the other threads to prevent unnecessary work being done).

    0 讨论(0)
  • 2020-11-22 14:55

    Have a look at various solutions.

    1. join() API has been introduced in early versions of Java. Some good alternatives are available with this concurrent package since the JDK 1.5 release.

    2. ExecutorService#invokeAll()

      Executes the given tasks, returning a list of Futures holding their status and results when everything is completed.

      Refer to this related SE question for code example:

      How to use invokeAll() to let all thread pool do their task?

    3. CountDownLatch

      A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

      A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.

      Refer to this question for usage of CountDownLatch

      How to wait for a thread that spawns it's own thread?

    4. ForkJoinPool or newWorkStealingPool() in Executors

    5. Iterate through all Future objects created after submitting to ExecutorService

    0 讨论(0)
  • 2020-11-22 14:56

    The approach I take is to use an ExecutorService to manage pools of threads.

    ExecutorService es = Executors.newCachedThreadPool();
    for(int i=0;i<5;i++)
        es.execute(new Runnable() { /*  your task */ });
    es.shutdown();
    boolean finished = es.awaitTermination(1, TimeUnit.MINUTES);
    // all tasks have finished or the time has been reached.
    
    0 讨论(0)
  • 2020-11-22 14:58

    The existing answers said could join() each thread.

    But there are several ways to get the thread array / list:

    • Add the Thread into a list on creation.
    • Use ThreadGroup to manage the threads.

    Following code will use the ThreadGruop approach. It create a group first, then when create each thread specify the group in constructor, later could get the thread array via ThreadGroup.enumerate()


    Code

    SyncBlockLearn.java

    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    /**
     * synchronized block - learn,
     *
     * @author eric
     * @date Apr 20, 2015 1:37:11 PM
     */
    public class SyncBlockLearn {
        private static final int TD_COUNT = 5; // thread count
        private static final int ROUND_PER_THREAD = 100; // round for each thread,
        private static final long INC_DELAY = 10; // delay of each increase,
    
        // sync block test,
        @Test
        public void syncBlockTest() throws InterruptedException {
            Counter ct = new Counter();
            ThreadGroup tg = new ThreadGroup("runner");
    
            for (int i = 0; i < TD_COUNT; i++) {
                new Thread(tg, ct, "t-" + i).start();
            }
    
            Thread[] tArr = new Thread[TD_COUNT];
            tg.enumerate(tArr); // get threads,
    
            // wait all runner to finish,
            for (Thread t : tArr) {
                t.join();
            }
    
            System.out.printf("\nfinal count: %d\n", ct.getCount());
            Assert.assertEquals(ct.getCount(), TD_COUNT * ROUND_PER_THREAD);
        }
    
        static class Counter implements Runnable {
            private final Object lkOn = new Object(); // the object to lock on,
            private int count = 0;
    
            @Override
            public void run() {
                System.out.printf("[%s] begin\n", Thread.currentThread().getName());
    
                for (int i = 0; i < ROUND_PER_THREAD; i++) {
                    synchronized (lkOn) {
                        System.out.printf("[%s] [%d] inc to: %d\n", Thread.currentThread().getName(), i, ++count);
                    }
                    try {
                        Thread.sleep(INC_DELAY); // wait a while,
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                System.out.printf("[%s] end\n", Thread.currentThread().getName());
            }
    
            public int getCount() {
                return count;
            }
        }
    }
    

    The main thread will wait for all threads in the group to finish.

    0 讨论(0)
  • 2020-11-22 15:00

    Although not relevant to OP's problem, if you are interested in synchronization (more precisely, a rendez-vous) with exactly one thread, you may use an Exchanger

    In my case, I needed to pause the parent thread until the child thread did something, e.g. completed its initialization. A CountDownLatch also works well.

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