JUC同步工具类

信号量

Java.util.concurrent.Semaphore是一种计数信号量,用来控制同时访问某个特定资源的操作数量,或者同时执行指定操作的数量。

1
Semaphore semaphore = new Semaphore(1);

新建信号量时,会初始化一组凭证(permits),线程在调用acquire会消费一个凭证,在调用release会释放一个凭证。

注意new Semaphore(1)默认是非公平的,也就是不能保证等待获取凭证越久的线程能先获得。需要公平的信号量时,使用new Semaphore(1,true)

信号量

用途

  1. 许可为1的信号量可以作为互斥体,可以制造一个临界区,同一时间只允许一个线程访问。
1
2
3
4
5
6
Semaphore semaphore = new Semaphore(1);
//临界区
semaphore.acquire();
...something
semaphore.release();
  1. Semaphore可以实现资源池,限制连接数,如数据库连接池。

闭锁

闭锁(CountDownLatch)相当于一扇关着的门,当满足某个条件时,才打开这扇门让线程通过。

1
CountDownLatch latch = new CountDownLatch(3);

闭锁初始化时,需要提供一个计数值,这个值在调用countDown时减一,只要减到0时,CountDownLatchawait方法才会放行。
latches

用途

  1. 确保某些活动直到其他活动都完成后才继续执行。
    1. 确保所需资源全部初始化。
    2. 确保某个服务依赖的其他服务全部正常启动。
    3. 等待所有(游戏)参与者准备就绪。

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class CountDownLatchExample {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3);
new Thread(new CountDownLatchWaiter(countDownLatch)).start();
new Thread(new CountDownLatchDecrease(countDownLatch)).start();
}
public static class CountDownLatchWaiter implements Runnable {
private final CountDownLatch countDownLatch;
public CountDownLatchWaiter(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
countDownLatch.await();
System.out.println("CountDownLatch wait finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static class CountDownLatchDecrease implements Runnable {
private final CountDownLatch countDownLatch;
public CountDownLatchDecrease(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
System.out.println("current count " + countDownLatch.getCount());
countDownLatch.countDown();
System.out.println("current count " + countDownLatch.getCount());
Thread.sleep(1000);
countDownLatch.countDown();
System.out.println("current count " + countDownLatch.getCount());
Thread.sleep(1000);
countDownLatch.countDown();
System.out.println("current count " + countDownLatch.getCount());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

输出结果

1
2
3
4
5
current count 3
current count 2
current count 1
current count 0
CountDownLatch wait finished

栅栏

栅栏与闭锁类似,它能阻塞一组线程直到某个事件的发生。栅栏的意义是所有线程都必须到达栅栏的位置,才能继续执行。

1
CyclicBarrier barrier = new CyclicBarrier(3);

创建栅栏时,需要指定需要等待的线程数量,只有到达栅栏位置的线程数大于等于该值,才能通行。

cyclicbarrie

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
new Thread(new CyclicBarrierWaiter(cyclicBarrier)).start();
new Thread(new CyclicBarrierWaiter(cyclicBarrier)).start();
new Thread(new CyclicBarrierWaiter(cyclicBarrier)).start();
}
private static class CyclicBarrierWaiter implements Runnable {
private CyclicBarrier cyclicBarrier;
public CyclicBarrierWaiter(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " await");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + " passed");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
}

输出结果

1
2
3
4
5
6
Thread-2 await
Thread-1 await
Thread-0 await
Thread-0 passed
Thread-1 passed
Thread-2 passed

栅栏与闭锁

不同点栅栏闭锁
等待的类型等待线程等待事件
线程数量限制指定的线程数量可以在栅栏位置await任意数量的线程可以在闭锁处await
是否可重置可以不可以