CountdownLatch

CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CountDownLatchTest{
static CountDownLatch c = new CountDownLatch(2);

public static void main(String[] args){
new Thread(new Runnable(){
@Override
public void run(){
System.out.println(1);
c.countDown();
System.out.println(2);
c.countDown();
}
}).start();

try {
c.await();
} catch (InterruptedException e) {
}
System.out.println(3);
}
}

还可以通过创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,随后调用countDown()方法来同时启动多个线程。

CyclicBarrier

同步屏障CyclicBarrier可以让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CyclicBarrierTest {
static CyclicBarrier c = new CyclicBarrier(2);

public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
try{
c.await();
} catch (Exception e){
}
System.out.println(1);
}
}).start();

try{
c.await();
}catch (Exception e){
}
System.out.println(2);
}
}

CyclicBarrier和CountDownLatch的区别

CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计数器,并让线程重新执行一次。

Semaphore

Semaphore是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。Semaphore的构造方法接受一个整型的数字,表示可用的许可证数量,线程使用acquire()方法获取一个许可证,如果没有许可证能够获得则被阻塞,使用完后调用release()方法归还许可证。还可以使用tryAcquire()方法尝试获取许可证,若获取成功,则立即返回true,若获取失败,则立即返回false。

Semaphore可以用于流量控制,特别是公用资源有限的应用场景,比如数据库连接。如果线程数有几十个,而数据库的连接只有十个,那么就可以使用Semaphore控制同时获取数据库连接的个数。

参考资料