等到所有线程完成他们在java中的工作

时间:2011-10-29 13:40:24

标签: java multithreading wait

我正在编写一个包含5个线程的应用程序,它们可以同时从Web获取一些信息并填充缓冲类中的5个不同字段。
当所有线程完成工作时,我需要验证缓冲区数据并将其存储在数据库中 我该怎么做(当所有线程完成工作时收到警报)?

17 个答案:

答案 0 :(得分:100)

我采用的方法是使用ExecutorService来管理线程池。

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.

答案 1 :(得分:44)

你可以join到线程。连接阻塞直到线程完成。

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

请注意,join会引发InterruptedException。如果发生这种情况,您将不得不决定该怎么做(例如,尝试取消其他线程以防止不必要的工作)。

答案 2 :(得分:19)

了解各种解决方案。

  1. join() API已在早期版本的Java中引入。自JDK 1.5发布以来,这个concurrent包提供了一些很好的替代方案。

  2. ExecutorService#invokeAll()

      

    执行给定的任务,在完成所有任务后返回持有其状态和结果的Futures列表。

    有关代码示例,请参阅此相关SE问题:

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

  3. CountDownLatch

      

    允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。

         

    使用给定的计数初始化 CountDownLatch 。由于countDown()方法的调用,await方法阻塞直到当前计数达到零,之后释放所有等待的线程,并且任何后续的await调用立即返回。这是一次性现象 - 计数无法重置。如果您需要重置计数的版本,请考虑使用 CyclicBarrier

    有关CountDownLatch

    的使用,请参阅此问题

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

  4. {li>

    ForkJoinPoolnewWorkStealingPool()中的Executors

  5. 迭代提交到ExecutorService后创建的所有Future个对象

答案 3 :(得分:10)

除了其他人提出的Thread.join()之外,java 5引入了执行程序框架。在那里,您不使用Thread个对象。相反,您将CallableRunnable个对象提交给执行者。有一个特殊的执行程序,用于执行多个任务并无序返回结果。这是ExecutorCompletionService

ExecutorCompletionService executor;
for (..) {
    executor.submit(Executors.callable(yourRunnable));
}

然后您可以重复调用take(),直到不再有Future<?>个对象返回,这意味着所有对象都已完成。


根据您的情况,可能相关的另一件事是CyclicBarrier

  

一种同步辅助工具,允许一组线程全部等待彼此到达公共障碍点。 CyclicBarriers在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障称为循环,因为它可以在等待线程释放后重新使用。

答案 4 :(得分:9)

另一种可能性是CountDownLatch对象,它对于简单情况很有用:因为您事先知道线程数,所以使用相关计数初始化它,并将对象的引用传递给每个线程。
完成任务后,每个线程调用CountDownLatch.countDown(),递减内部计数器。主线程在启动所有其他线程后,应该执行CountDownLatch.await()阻塞调用。一旦内部计数器达到0,它就会被释放。

注意使用此对象,也可以抛出InterruptedException

答案 5 :(得分:8)

你做

for (Thread t : new Thread[] { th1, th2, th3, th4, th5 })
    t.join()

在此for循环之后,您可以确保所有线程都已完成其工作。

答案 6 :(得分:4)

将Thread-objects存储到某个集合(如List或Set)中,然后在线程启动后循环遍历集合并在线程上调用join()

答案 7 :(得分:2)

虽然与OP的问题无关,但如果您对只有一个线程的同步感兴趣(更确切地说,是一个rendez-vous),您可以使用Exchanger

在我的情况下,我需要暂停父线程,直到子线程执行某些操作,例如完成了初始化。 CountDownLatch也很有用。

答案 8 :(得分:2)

您可以使用Threadf#join方法来实现此目的。

答案 9 :(得分:1)

执行程序服务可用于管理多个线程,包括状态和完成。见http://programmingexamples.wikidot.com/executorservice

答案 10 :(得分:1)

试试这个,会有用。

  Thread[] threads = new Thread[10];

  List<Thread> allThreads = new ArrayList<Thread>();

  for(Thread thread : threads){

        if(null != thread){

              if(thread.isAlive()){

                    allThreads.add(thread);

              }

        }

  }

  while(!allThreads.isEmpty()){

        Iterator<Thread> ite = allThreads.iterator();

        while(ite.hasNext()){

              Thread thread = ite.next();

              if(!thread.isAlive()){

                   ite.remove();
              }

        }

   }

答案 11 :(得分:1)

我遇到了类似的问题,最终使用了Java 8 parallelStream。

requestList.parallelStream().forEach(req -> makeRequest(req));

它非常简单易读。 在幕后它使用默认的JVM的fork连接池,这意味着它将在继续之前等待所有线程完成。对于我的情况,它是一个简洁的解决方案,因为它是我的应用程序中唯一的parallelStream。如果您同时运行多个parallelStream,请阅读以下链接。

有关并行流here的更多信息。

答案 12 :(得分:0)

说的现有答案可能join()每个线程。

但是有几种获取线程数组/列表的方法:

  • 在创建时将线程添加到列表中。
  • 使用ThreadGroup管理线程。

以下代码将使用ThreadGruop方法。它首先创建一个组,然后在创建每个线程时在构造函数中指定该组,然后可以通过ThreadGroup.enumerate()

获取线程数组。

代码

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;
        }
    }
}

主线程将等待组中的所有线程结束。

答案 13 :(得分:0)

我创建了一个小的辅助方法,以等待一些线程完成:

public static void waitForThreadsToFinish(Thread... threads) {
        try {
            for (Thread thread : threads) {
                thread.join();
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

答案 14 :(得分:0)

等待/阻塞线程主线程,直到其他一些线程完成其工作。

正如@Ravindra babu所说的那样,可以通过多种方式来实现,但要举例说明。

  • java.lang.Thread。join() 因为:1.0

    public static void joiningThreads() throws InterruptedException {
        Thread t1 = new Thread( new LatchTask(1, null), "T1" );
        Thread t2 = new Thread( new LatchTask(7, null), "T2" );
        Thread t3 = new Thread( new LatchTask(5, null), "T3" );
        Thread t4 = new Thread( new LatchTask(2, null), "T4" );
    
        // Start all the threads
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    
        // Wait till all threads completes
        t1.join();
        t2.join();
        t3.join();
        t4.join();
    }
    
  • java.util.concurrent.CountDownLatch 自:1.5

    • .countDown()«减少锁存器组的计数。
    • .await()«等待方法将阻塞,直到当前计数达到零为止。

    如果您创建了latchGroupCount = 4,则应该调用countDown() 4次以使计数为0。因此,await()将释放阻塞线程。

    public static void latchThreads() throws InterruptedException {
        int latchGroupCount = 4;
        CountDownLatch latch = new CountDownLatch(latchGroupCount);
        Thread t1 = new Thread( new LatchTask(1, latch), "T1" );
        Thread t2 = new Thread( new LatchTask(7, latch), "T2" );
        Thread t3 = new Thread( new LatchTask(5, latch), "T3" );
        Thread t4 = new Thread( new LatchTask(2, latch), "T4" );
    
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    
        //latch.countDown();
    
        latch.await(); // block until latchGroupCount is 0.
    }
    

线程类LatchTask的示例代码。要测试方法,请使用joiningThreads();latchThreads();来自主要方法。

class LatchTask extends Thread {
    CountDownLatch latch;
    int iterations = 10;
    public LatchTask(int iterations, CountDownLatch latch) {
        this.iterations = iterations;
        this.latch = latch;
    }

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " : Started Task...");

        for (int i = 0; i < iterations; i++) {
            System.out.println(threadName + " : " + i);
            MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
        }
        System.out.println(threadName + " : Completed Task");
        // countDown() « Decrements the count of the latch group.
        if(latch != null)
            latch.countDown();
    }
}
  • CyclicBarriers一种同步辅助工具,它允许一组线程彼此等待到达一个公共的障碍点。CyclicBarriers在涉及固定大小线程的程序中很有用,这些线程必须偶尔等待。该屏障称为循环屏障,因为它可以在释放等待线程之后重新使用。
    CyclicBarrier barrier = new CyclicBarrier(3);
    barrier.await();
    
    例如,请参考此Concurrent_ParallelNotifyies类。

  • 执行器框架:我们可以使用ExecutorService创建线程池,并使用Future跟踪异步任务的进度。

    • submit(Runnable)submit(Callable),它们返回Future对象。通过使用future.get()函数,我们可以阻塞主线程,直到工作线程完成其工作为止。

    • invokeAll(...)-返回Future对象的列表,通过它们可以获取每个Callable的执行结果。

Find example使用可运行的接口,可与Executor框架一起使用。


@另请参见

答案 15 :(得分:0)

我遇到了类似的情况,我必须等到所有子线程完成执行,然后才能获得每个子线程的状态结果..因此我需要等到所有子线程完成。

下面是我使用多线程的代码

 public static void main(String[] args) {
        List<RunnerPojo> testList = ExcelObject.getTestStepsList();//.parallelStream().collect(Collectors.toList());
        int threadCount = ConfigFileReader.getInstance().readConfig().getParallelThreadCount();
        System.out.println("Thread count is : =========  " + threadCount); // 5

        ExecutorService threadExecutor = new DriverScript().threadExecutor(testList, threadCount);


        boolean isProcessCompleted = waitUntilCondition(() -> threadExecutor.isTerminated()); // Here i used waitUntil condition 

        if (isProcessCompleted) {
            testList.forEach(x -> {
                System.out.println("Test Name: " + x.getTestCaseId());
                System.out.println("Test Status : " + x.getStatus());
                System.out.println("======= Test Steps ===== ");

                x.getTestStepsList().forEach(y -> {
                    System.out.println("Step Name: " + y.getDescription());
                    System.out.println("Test caseId : " + y.getTestCaseId());
                    System.out.println("Step Status: " + y.getResult());
                    System.out.println("\n ============ ==========");
                });
            });
        }

下面的方法是用于列表的并行处理

// This method will split my list and run in a parallel process with mutliple threads
    private ExecutorService threadExecutor(List<RunnerPojo> testList, int threadSize) {
        ExecutorService exec = Executors.newFixedThreadPool(threadSize);
        testList.forEach(tests -> {
            exec.submit(() -> {
                driverScript(tests);
            });
        });
        exec.shutdown();
        return exec;
    }

这是我的等待方法:在这里你可以等到你的条件在 do while 循环中满足。在我的情况下,我等待了一些最大超时。 这将继续检查,直到您的 threadExecutor.isTerminated()true,轮询周期为 5 秒。

    static boolean waitUntilCondition(Supplier<Boolean> function) {
        Double timer = 0.0;
        Double maxTimeOut = 20.0;

        boolean isFound;
        do {
            isFound = function.get();
            if (isFound) {
                break;
            } else {
                try {
                    Thread.sleep(5000); // Sleeping for 5 sec (main thread will sleep for 5 sec)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                timer++;
                System.out.println("Waiting for condition to be true .. waited .." + timer * 5 + " sec.");
            }
        } while (timer < maxTimeOut + 1.0);

        return isFound;
    }

答案 16 :(得分:-1)

在主线程中使用:while(!executor.isTerminated()); 在从executor服务启动所有线程之后放入这行代码。这只会在执行程序启动的所有线程完成后才启动主线程。一定要调用executor.shutdown();在上述循环之前。