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

本文介绍了在Java中使用CountDownLatch和awaitTermination两种方法来等待线程池中所有任务执行完毕,包括线程池管理、批量任务处理和并发测试场景,并强调了注意事项如线程安全和避免死锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用场景

  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);
    }
}
结果

在这里插入图片描述

原理和注释:
  • 创建一个固定大小的线程池,并使用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);
    }
}
运行截图

在这里插入图片描述

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

需要注意的点

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

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

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

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

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

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

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

1. Java Executor Framework:Java Executor Framework是Java中提供的线程池框架,可以实现异步任务执行。可以通过以下代码实现线程池和异步任务执行: ``` ExecutorService executor = Executors.newFixedThreadPool(5); // 异步任务 Runnable task = new Runnable() { @Override public void run() { // 执行任务 } }; // 提交任务 executor.submit(task); // 关闭线程池 executor.shutdown(); ``` 2. Spring Task Executor:Spring框架中提供了TaskExecutor接口,可以实现异步任务执行。可以通过以下代码实现异步任务执行: ``` @Autowired TaskExecutor taskExecutor; // 异步任务 Runnable task = new Runnable() { @Override public void run() { // 执行任务 } }; // 提交任务 taskExecutor.execute(task); ``` 3. Java Future和Callable:Java中提供了Future和Callable接口,可以实现异步任务执行。可以通过以下代码实现异步任务执行: ``` ExecutorService executor = Executors.newFixedThreadPool(5); // 异步任务 Callable<String> task = new Callable<String>() { @Override public String call() throws Exception { // 执行任务 return "任务执行结果"; } }; // 提交任务 Future<String> future = executor.submit(task); // 获取任务执行结果 String result = future.get(); // 关闭线程池 executor.shutdown(); ``` 4. Java CompletableFuture:Java8中提供了CompletableFuture类,可以实现异步任务执行。可以通过以下代码实现异步任务执行: ``` // 异步任务 CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 执行任务 }); // 获取任务执行结果 future.get(); ``` 5. 自定义线程池:可以通过自定义线程池实现异步任务执行。可以通过以下代码实现异步任务执行: ``` // 自定义线程池 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); // 异步任务 Runnable task = new Runnable() { @Override public void run() { // 执行任务 } }; // 提交任务 executor.submit(task); // 关闭线程池 executor.shutdown(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值