多线程并发之CountDownLatch

555 阅读2分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

场景

这边模拟一个场景教室里面有6个同学+1个值日生,值日生需要等到教室里所有其他同学都离开之后完成关门的任务。然后根据需求模拟出下面的代码

public class CountDownLatchDemo {
    public static void main(String[] args) {
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "号同学离开教室~~~");
            }, String.valueOf(i)).start();
        }
        System.out.println("值日生关门走啦~~~");
    }
}

运行结果:

1号同学离开教室~~~
值日生关门走啦~~~
2号同学离开教室~~~
3号同学离开教室~~~
6号同学离开教室~~~
5号同学离开教室~~~
4号同学离开教室~~~

可以看到由于多线程环境下,可能其他线程还没有执行完成(其他同学还没有离开教室),main线程就先执行了值日生关门走啦的操作,于是为了解决这个问题我们引入了java.util.concurrent包下的CountDownLatch

  • CountDownLatch有一个正数计数器,countDown()方法对计数器做减操作,await()方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时。

闭锁(倒计时锁)的作用

  • 协调线程,让某个线程等到倒计时结束再开始执行
  • 可以应用于控制线程执行的先后顺序

源码分析

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

可以看到CountDownLatch中维护了一个内部类Sync,而Sync继承自AbstractQueuedSynchronizer, 而AbstractQueuedSynchronizer中有一个变量private volatile int state;保证了state变量的可见性

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "号同学离开教室~~~");
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        countDownLatch.await();
        System.out.println("值日生关门走啦~~~");
    }
}

运行结果:

1号同学离开教室~~~
4号同学离开教室~~~
6号同学离开教室~~~
3号同学离开教室~~~
2号同学离开教室~~~
5号同学离开教室~~~
值日生关门走啦~~~