Java基础-0x06:CountDownLatch/CyclicBarrier/Semaphore的使用

s

JUC

CountDownLatch/CyclicBarrier/Semaphore 如何使用

  • CountDownLatch(闭锁)
  • CyclicBarrier(栅栏)
  • Semaphore(信号量)

CountDownLatch

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.

用给定的计数初始化闭锁。 由于count down方法的调用,await方法将阻塞到当前计数为零为止。之后,释放所有等待的线程,并立即返回任何后续的“await”调用。

使用的是CountDownLatch.countDown()+CountDownLatch.await()两个方法。

小Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CountDownLatchDemo {
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t 国被灭");
countDownLatch.countDown();
},CountryEnum.forEach_CountryEnum(i).getMessage()).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t Down...");
}
}

Enum类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public enum CountryEnum {
/**
* 国家名称
*/
ONE(1,"齐"),TWO(2,"楚"),THREE(3,"燕"),FORE(4,"赵"),FIVE(5,"魏"),SIX(6,"韩");

@Getter private Integer code;
@Getter private String message;

CountryEnum(Integer code,String message){
this.code = code;
this.message = message;
}

public static CountryEnum forEach_CountryEnum(int index){
CountryEnum[] myArray = CountryEnum.values();
for(CountryEnum countryEnum:myArray){
if(index == countryEnum.getCode()){
return countryEnum;
}
}
return null;
}
}

当CountDownLatch中初始化的数字中减为0,才会执行接下来的线程。

CyclicBarrier

CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。他要做的事情时让一组线程达到一个屏障(也可以叫同步点)是被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过Cyclibarrierawait()方法。

这是一个小Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("召唤神龙");
});
for (int i = 1; i <= 7; i++) {
int finalI = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+
"\t 这是第"+ finalI +"颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}

CyclicBarrier与CountDownLatch的区别就是一个时顺序执行,一个时有一个屏障点,屏障点之前的线程可以不按顺序执行。

Semaphore

信号量主要用于两个目的:

  • 多个资源共享的互斥使用
  • 并发线程数的控制

SemaphoreDemo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 6; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+
"\t 以抢占资源");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+
"\t 三秒后释放资源");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}

当一个线程使用了资源的时候,在前面调用semaphore.acquire()方法,前面在构造Semaphore的时候填入的permits参数就会减1,然后等资源使用完成,释放资源的时候会调用semaphore.release()方法,下一个线程就可以进来继续使用该资源。类似于海底捞人满了,接待员告诉你可以在外面等一下,里面人吃完了你就能进去吃饭了。

Reference

图片来自:去哪儿