19. 线程通信-监听异步线程结束

java 多线程系列文章列表, 请查看目录: 《java 多线程学习笔记》

在企业开发中, 采用异步线程可以提升系统性能. 但是在异步线程开发中, 有时主线程需要监听异步线程何时执行结束, 然后再做一些其它操作. java 中有两种方式监听异步线程的结束: CountDownLatch 和 join.

1. CountDownLatch 方式

1.1 自定义线程类

  • 自定义线程类需要添加一个CountDownLatch 计数器, 建议在构造方法赋值
  • 务必保证CountDownLatch 自减操作在finally 代码快中
class MyThread extends Thread{

    // 计数器
    private CountDownLatch countDownLatch;

    // 创建线程实例时, 初始化计数器
    public MyThread(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    // 计数器自减操作必须放在finally中, 保证一定会执行
    @Override
    public void run() {
        try {
            Thread.sleep(2000l);
            System.out.println(Thread.currentThread().getName() + "-执行..");
        } catch (Exception ex) {

        }finally {
            // 放到finally块儿中, 确保一定会执行
            countDownLatch.countDown();
        }
    }
}

1.2 测试用例

  • CountDownLatch 的值务必保证和需要监控的多线程的数量一致
  • countDownLatch.await() 会阻塞主线程, 等监听的异步线程均结束后, 继续进行
public static void main(String[] args) throws InterruptedException {

    // 线程数量
    int threadNum = 5;

    // CountDownLatch 初始化值必须和线程数量一致
    CountDownLatch countDownLatch = new CountDownLatch(threadNum);

    // 创建固定数量的线程并启动
    for (int i = 0; i < threadNum; i++) {
        new MyThread(countDownLatch).start();
    }

    System.out.println("执行主线程逻辑, 主线程开始等待多线程执行结束...");

    // 主线程等待异步线程结束
    countDownLatch.await();

    System.out.println("异步线程全部执行结束, 继续执行主线程逻辑");

}

1.3 测试输出

执行主线程逻辑, 主线程开始等待多线程执行结束...
Thread-0-执行..
Thread-1-执行..
Thread-2-执行..
Thread-3-执行..
Thread-4-执行..
异步线程全部执行结束, 继续执行主线程逻辑

2. join 方式

  • Thread 的提供了join 方法, 用于一个线程监听另一个线程结束的方法.
  • join方法通常用于监听一个异步线程的情况, 不用于监听多个异步线程.
  • join方式相较于CountDownLatch, 需要持有异步线程的引用. 耦合性较强.

2.1 join API

方法签名 方法描述
public final void join() throws InterruptedException 等待异步线程结束, 一直等待, 不超时
public final synchronized void join(long millis) 等待时长为millis毫秒, 超时之后不再等待, 也不抛出异常
public final synchronized void join(long millis, int nanos) 操作系统本身无法精确到纳秒, 所以不常使用

2.2 测试用例

public static void main(String[] args) throws InterruptedException {

    // 1. 创建异步线程, 并启动
    Thread thread = new Thread(){
        @Override
        public void run() {
            try {
                System.out.println("异步线程休眠第1秒.");
                Thread.sleep(1000l);
                System.out.println("异步线程休眠第2秒..");
                Thread.sleep(1000l);
                System.out.println("异步线程休眠第3秒..");
                Thread.sleep(1000l);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    };
    thread.start();

    // 主线程休眠1秒后再执行, 先让异步线程执行1秒
    Thread.sleep(1000l);
    System.out.println("主线程执行业务逻辑, 开始等待异步线程执行结束..");
    
    // 主线程开始等待
    thread.join();
    
    System.out.println("异步线程执行结束, 主线程继续执行业务逻辑");
}

2.3 测试输出

异步线程休眠第1秒.
主线程执行业务逻辑, 开始等待异步线程执行结束..
异步线程休眠第2秒..
异步线程休眠第3秒..
异步线程执行结束, 主线程继续执行业务逻辑
发布了321 篇原创文章 · 获赞 676 · 访问量 147万+

猜你喜欢

转载自blog.csdn.net/zongf0504/article/details/100186205
今日推荐