前言:

本文内容:CountDownLatch、CyclicBarrier、Semaphore

推荐免费JUC并发编程视频:【狂神说Java】JUC并发编程最新版通俗易懂_哔哩哔哩_bilibili

CountDownLatch

允许一个或多个线程等待直到其他线程中执行的一组操作完成的同步辅助

减法计数器

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
package com.jokerdig.add;

import java.util.concurrent.CountDownLatch;

/**
* @author Joker大雄
* @data 2022/8/20 - 10:45
**/
// 计数器
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
// 倒计时 总数是5
CountDownLatch downLatch = new CountDownLatch(5);

for (int i= 1;i<=5;i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"->end");
downLatch.countDown(); // 减一
}).start();
}
downLatch.await();// 等待计数器归零在向下执行

System.out.println("计数器已经归零");
}
}

运行结果

1
2
3
4
5
6
Thread-2->end
Thread-3->end
Thread-0->end
Thread-1->end
Thread-4->end
计数器已经归零

原理

  • countDown(); 数量减1
  • await();` 等待计数器归零在向下执行

每次线程调用countDown()数量减1,计数器变为0,await()就会被唤醒,继续执行。

CyclicBarrier

允许一组线程全部等待彼此达到共同屏屏障点的同步辅助,循环阻塞在涉及固定大小的线程中很有用,这些线程必须偶尔等待彼此;屏障被称为循环,因为它可以在等待线程被释放之后重新使用。

加法计数器

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
package com.jokerdig.add;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
* @author Joker大雄
* @data 2022/8/20 - 10:56
**/
public class CyclicBarrierDemo {
public static void main(String[] args) {
// 例子:集齐7颗龙珠召唤神龙
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("召唤神龙!");
});

for(int i =1;i<=7;i++){
final int temp = i; // 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
// lambda表达式无法直接操作i
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"收集第"+temp+"颗龙珠");
try {
cyclicBarrier.await(); //等待
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}

}).start();
}
}
}

运行结果

1
2
3
4
5
6
7
8
9
10
Thread-0收集第1颗龙珠
Thread-5收集第6颗龙珠
Thread-2收集第3颗龙珠
Thread-1收集第2颗龙珠
Thread-6收集第7颗龙珠
Thread-3收集第4颗龙珠
Thread-4收集第5颗龙珠
召唤神龙!

Process finished with exit code 0

Semaphore

Semaphore:信号量

一个计数信号量,在概念上,信号量维持一组许可证,如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它。

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
package com.jokerdig.add;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
* @author Joker大雄
* @data 2022/8/20 - 11:07
**/
public class SemaphoreDemo {
public static void main(String[] args) {
// 例子:抢车位
// 线程数量 停车位
Semaphore semaphore = new Semaphore(3);

for (int i=1;i<=6;i++){
new Thread(()->{
// acquire() 得到
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"抢到了车位");
TimeUnit.SECONDS.sleep(2); // 假设停了两秒
System.out.println(Thread.currentThread().getName()+"离开了车位");

} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// release() 释放
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
2抢到了车位
1抢到了车位
3抢到了车位
1离开了车位
2离开了车位
4抢到了车位
5抢到了车位
3离开了车位
6抢到了车位
6离开了车位
4离开了车位
5离开了车位

Process finished with exit code 0

原理

  • acquire() 得到,如果位置已经满了,开始等待,直到被释放为止;
  • release() 释放,会将当前的信号量释放+1,然后唤醒等待的线程;

作用:多个共享资源互斥的时候使用,并发限流,控制最大线程数!