java线程池开发的时候如何让主线程等待子线程执行结束后结束

我们在直接使用Thread线程类的时候可以用join方法解决主线程等待子线程执行完毕的需求,但是在实际开发中我们用的大多是线程池,没有join方法给我们调用。这种情况JAVA提供了两种解决方法。

第一种:CountDownLatch

CountDownLatch使用比较直白,它直观的伴随着子线程的结束而将自身的任务数递减,到0时主线程继续,使用的时候不要倒错包。

java.util.concurrent.CountDownLatch

使用它,你只需要在向线程池提交任务前,new一个CountDownLatch,并指定任务总数大小就可以,比如提交5个任务,你就new一个5个count的

CountDownLatch countDownLatch = new CountDownLatch(5);

随后在提交的任务中,末尾该任务逻辑执行结束的地方调用,减一方法,它的作用就是告诉CountDownLatch已经完成某个任务并把任务数递减

countDownLatch.countDown();

最后在主线程的末尾使用等待方法,它会等待任务数为0的时候解除线程阻塞

countDownLatch.await();

同时它也提供了获取当前任务数的方法

countDownLatch.getCount()

第二种:CyclicBarrier

CyclicBarrier是当所有子线程执行到某一步的时候停止,并等待其他子线程,当所有子线程执行到特定地方后,所有线程开始继续。

public class CycleBarrierTest {
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
        // 当计数器为0时,立即执行
        @Override
        public void run() {
            System.out.println("汇总线程:" + Thread.currentThread().getName() + " 任务合并。");
        }
    });

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 将线程A添加到线程池
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程A:" + Thread.currentThread().getName() + "执行任务。");
                    System.out.println("线程A:到达屏障点");
                    cyclicBarrier.await();
                    System.out.println("线程A:退出屏障点");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        // 将线程B添加到线程池
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程B:" + Thread.currentThread().getName() + "执行任务。");
                    System.out.println("线程B:到达屏障点");
                    cyclicBarrier.await();
                    System.out.println("线程B:退出屏障点");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        // 关闭线程池
        executorService.shutdown();
    }
}
线程A:pool-1-thread-1执行任务。
线程A:到达屏障点
线程B:pool-1-thread-2执行任务。
线程B:到达屏障点
汇总线程:pool-1-thread-2 任务合并。
线程B:退出屏障点
线程A:退出屏障点

一般不用CyclicBarrier,它的缺点很明显,当所有的线程达到某一步的时候,阻塞就失效了,后面的代码并不会在主线程前结束


除了上面两种,其实在使用的时候,还有一种方法,只不过很少会用到啊,因为它比较鸡肋,上面两种方法特点是直接干涉了线程池内部任务运行时的流程,而我现在说的这种方法是无法直接干涉子线程,常是来观察子线程运行的状态,在运行的流程上和,上面CyclicBarrier有点像,很少用,通常都是用在对任务本身的状态做相关操作时才会用。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class ThreadPoolExample {
    private static ExecutorService threadPool = Executors.newFixedThreadPool(5);

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        List<Future<String>> futures = new ArrayList<>();
        
        // 提交任务到线程池
        for (int i = 0; i < 10; i++) {
            Callable<String> task = new MyTask();
            Future<String> future = threadPool.submit(task);
            futures.add(future);
        }
        
        // 等待任务完成,可以根据需要设置超时时间
        for (Future<String> future : futures) {
            try {
                String result = future.get(); // 等待任务完成并获取结果
                System.out.println("Task result: " + result);
            } catch (InterruptedException | ExecutionException e) {
                // 处理任务中断或执行异常的情况
                e.printStackTrace();
            }
        }
        
        // 关闭线程池
        threadPool.shutdown();
    }
}

上述示例中,使用Future对象来获取任务的执行结果,并在任务完成后执行相应的代码。可以在获取结果的时候进行判断,如果任务被中止或停止,可以在相应的catch块中添加自定义的代码来处理。例如,可以记录日志、执行清理操作等。
需要注意的是,Future对象的get()方法是阻塞的,会等待任务执行完成并获取结果。如果想设置超时时间,可以使用get(long timeout, TimeUnit unit)方法,并在指定的时间内获取结果。如果任务超时未完成,会抛出TimeoutException异常。

try {
    String result = future.get(1, TimeUnit.SECONDS); // 设置超时时间为1秒
    System.out.println("Task result: " + result);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
    // 处理任务中断、执行异常或超时的情况
    e.printStackTrace();
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值