两种方案实现等待线程池结束后执行后面的业务代码

使用场景

  1. 批量任务处理:当需要并发执行多个任务,然后等待所有任务执行完毕后进行下一步操作时,可以使用这两种方法来等待所有任务执行完毕。

  2. 线程池管理:在使用线程池执行任务时,有时需要等待所有任务执行完毕后再关闭线程池,可以使用这两种方法来实现这一需求。

  3. 并发测试:在并发测试中,有时需要等待所有测试线程执行完毕后再进行结果汇总和分析,这时可以使用这两种方法来等待所有测试线程执行完毕。

总之,无论是在需要等待多个任务执行完毕后再进行下一步操作的业务场景,还是在线程池管理或并发测试等技术领域,这两种方法都可以非常有用。它们能够帮助实现多线程任务的协同和管理,确保所有任务都执行完毕后再进行后续操作。

使用CountDownLatch的方案

代码
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.CountDownLatch;

public class ThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 5;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        CountDownLatch latch = new CountDownLatch(threadCount);
        List<Integer> list=new ArrayList<>();

        for (int i = 0; i < threadCount; i++) {
            int finalI = i;
            executor.submit(() -> {
                // 执行线程任务
                try {
                    System.out.println(finalI);
                    int i1 = get();
                    System.out.println("===============================");
                    list.add(i1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                // 任务执行完毕后,调用countDown()
                latch.countDown();
            });
        }
        // 等待所有线程执行完毕
        latch.await();
        // 关闭线程池
        executor.shutdown();
        System.out.println("******************************");
        System.out.println(list);
    }

    public static int get() throws InterruptedException {
        Thread.sleep(3000);
        return new Random().nextInt(30);
    }
}
结果

两种方案实现等待线程池结束后执行后面的业务代码_第1张图片

原理和注释:
  • 创建一个固定大小的线程池,并使用CountDownLatch来等待所有线程执行完毕。
  • 每个线程执行完毕后都会调用countDown()方法来减少计数器的值,当计数器的值为0时,await()方法就会返回,表示所有线程执行完毕。
  • 最后,调用shutdown()方法来关闭线程池。

使用awaitTermination的方案

代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.Random;

public class ThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 5;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        List<Integer> list=new ArrayList<>();

        for (int i = 0; i < threadCount; i++) {
            int finalI = i;
            executor.submit(() -> {
                // 执行线程任务
                try {
                    System.out.println(finalI);
                    int i1 = get();
                    System.out.println("===============================");
                    list.add(i1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); // 等待所有任务执行完毕

        System.out.println("************************************");
        System.out.println(list);

        // 所有任务执行完毕后会继续执行这里的代码
    }

    public static int get() throws InterruptedException {
        Thread.sleep(3000);
        return new Random().nextInt(30);
    }
}
运行截图

两种方案实现等待线程池结束后执行后面的业务代码_第2张图片

原理和注释:
  • 创建一个固定大小的线程池,并使用executor.shutdown()来关闭线程池。
  • 使用executor.awaitTermination()来等待所有任务执行完毕。当所有任务执行完毕后,awaitTermination会返回,然后可以继续执行后续的代码。

需要注意的点

在使用这两种方法等待线程执行完毕时,需要注意以下几点:

  1. 确保所有线程都能够正常执行完毕,否则可能会出现死锁等问题。

  2. 在使用CountDownLatch等待线程执行完毕时,需要在每个线程的任务执行完毕后调用countDown()方法,否则计数器的值不会减少,就会一直等待下去。

  3. 在使用awaitTermination等待线程执行完毕时,需要调用shutdown()方法来关闭线程池,否则线程池会一直等待新的任务到来,无法退出。

  4. 在使用awaitTermination等待线程执行完毕时,需要注意超时时间的设置,否则可能会一直等待下去。

  5. 在使用多线程时,需要注意线程安全问题,避免出现竞态条件等问题。

总之,在使用这两种方法等待线程执行完毕时,需要仔细考虑业务逻辑和线程安全问题,确保程序能够正确地执行。

你可能感兴趣的:(多线程,java,java,后端,多线程)