减少计数 CountDownLatch

CountDownLatch 类可以设置一个计数器,然后通过 countDown 方法来进行减 1 的操作,使用 await 方法等待计数器不大于 0,然后继续执行 await 方法之后的语句。具体步骤可以演化为定义一个类,减1操作,并等待到0,为0执行结果

常用的主要方法
await() 使当前线程在锁存器倒计数至零之前一直在等待,除非线程被中断
countDown()递减锁存器的计数,如果计数达到零,将释放所有等待的线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
// 创建CountDown对象并设置初始值
CountDownLatch countDownLatch = new CountDownLatch(6);
// 创建六个线程,模拟六个学生
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"离开教室");
// 计数 -1
countDownLatch.countDown();
},String.valueOf(i)).start();
}
// 等待,直到达到零
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"锁门");
}
}


循环栅栏 CyclicBarrier

该类是 允许一组线程 互相 等待,直到到达某个公共屏障点,在设计一组固定大小的线程的程序中,这些线程必须互相等待,因为barrier在释放等待线程后可以重用,所以称为循环barrier

CyclicBarrier 的构造方法第一个参数是目标障碍数,每次执行 CyclicBarrier 一次障碍数会+1,如果达到了目标障碍数,才会执行 cyclicBarrier.await()之后的语句。可以将 CyclicBarrier 理解为+1 操作(指与目标障碍数的距离)

常用的方法有:
await() 在所有的参与者都已经在此barrier上调用await方法之前一直等待。

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 class CyclicBarrirtTest {
// 创建固定值
private static final int NUMBER = 7;
public static void main(String[] args) {
// 每次执行 CyclicBarrier 一次障碍数会加一,如果达到了目标障碍数,才会执行 cyclicBarrier.await()之后的语句。
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("****集齐7颗龙珠就可以召唤神龙");
});

for (int i = 1; i <= 7; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+" 星龙被收集到了");
try {
// 计数 +1
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}

},String.valueOf(i)).start();
}
}
}

信号灯 Semaphore

一个计数信号量,从概念上将,信号量维护了一个许可集,如有必要,在许可可用前会阻塞每一个acquire(),然后在获取该许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动

具体常用的方法有:
acquire()从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断
release()释放一个许可,将其返回给信号量

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
public class SemaphoreTest {
public static void main(String[] args) {
//创建Semaphore,设置许可数量
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
// 抢占
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"抢到了车位");
// 设置停车时间
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
// 离开车位
System.out.println(Thread.currentThread().getName()+"------离开了车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}