Java 并发:用 CountDownLatch 和 CyclicBarrier 处理并发线程

Java并发:用CountDownLatch和CyclicBarrier处理并发线程

想象一种很常见的场景:

有一个操作需要N个线程同时做某种处理,另一个操作则需要等到这N个线程都执行完以后再执行。

思考一下,如果不用RxJava的zip方法,只用Java本身的类库,能不能轻松实现这种需求?

如果你脑海里第一反应是synchronizedwait,你就已经开始犯错了。


思考了一分钟,还是有些头疼?没关系,下面两位主角CountDownLatch 和 CyclicBarrier 出场了。

先介绍一下CountDownLatch 这个类:

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset.

也就是说:可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值 (countDown() 方法)。
你可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。

对于上面提出的问题。

public class CountDown extends Thread {
  static final CountDownLatch count = new CountDownLatch(10);

  @Override
  public void run() {
    try {
      System.out.println(Thread.currentThread().getName() + " is running");
      Thread.sleep(1000);//DO WTF u want
      count.countDown();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static void main(String args[]) throws InterruptedException {
    int n = 10;
    for (int i = 0; i < n; i++) {
      new CountDown().start();
    }
    count.await();
    System.out.println(" done !!!");

  }
}

输出:

Thread-0 is running
Thread-5 is running
Thread-3 is running
Thread-4 is running
Thread-2 is running
Thread-7 is running
Thread-8 is running
Thread-1 is running
Thread-6 is running
Thread-9 is running
 done !!!

是不是很优雅?

这个类真正强大的地方在于,它可以灵活的用于参数传递,去编写更多可以解决同步问题的代码,并带来一种比显式同步锁更加清晰的思路。


CountDownLatch这部分看懂了,另一个控制并发的神器CyclicBarrier也就容易懂了——CyclicBarrier 类用法类似,但它用于增加到一个固定值时触发一段操作
下面用LOL举例,进入英雄联盟这个游戏,需要

  1. 等待10个不同玩家读取进度条。
  2. 10个人都读取完进度条后开始游戏。
  3. 玩家开始购买装备。
top Created with Sketch.