CountDownLatch和Semaphore的区别和底层原理
CountDownLatch
CountDownLatch
表示计数器,可以给CountDownLatch
设置一个数字,一个线程调用CountDownLatch
的await()
将会被阻塞,其他线程可以调用CountDownLatch
的countDown()
方法来对CountDownLatch
中的数字减一,当数字被减为0后,所有的await的线程将会被唤醒。
对应的底层原理就是,调用await()
方法的线程会利用AQS排队,一旦数字被减为0,则会将AQS中的排队的线程依次唤醒。
countDownLatch.countDown(); 数量-1。
countDownLatch.await(); 等待计数器归零,然后再向下执行。
每次有线程调用countDown()数量-1,如果计数器变为0,countDownLatch.await()就会被唤醒,继续执行。
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
//总数是6,必须要执行任务的时候,在使用
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "Go out");
},String.valueOf(i)).start();
}
//等待计数器归零,再向下执行
countDownLatch.await();
System.out.println("Close Door");
}
}
如果没有countDownLatch.await();的时候,输出结果可能为:
Close Door
3Go out
2Go out
5Go out
1Go out
4Go out
0Go out
加了countDownLatch.await();之后,就会等待所有线程结束之后进行执行:
1 Go out
5 Go out
4 Go out
3 Go out
2 Go out
6 Go out
Close Door
Semaphore
Semaphore
表示信号量,可以设置许可的个数,表示同时允许最多多少个线程使用该信号量,通过acquire()
来获取许可,如果没有许可可用则线程阻塞,并通过AQS来排队,可以通过release()
方法来释放许可,当某个线程释放了某个许可后,会从AQS中正在排队的第一个线程开始依次唤醒,直到没有空闲许可。
semaphore.acquire(); 获得,如果已经满了,就等待,等待被释放为止。
semaphore.release(); 释放,会将当前的信号量释放 +1,然后唤醒等待的线程。
public class SemaphoreTest {
public static void main(String[] args) {
//线程数量:停车位例子! 限流的时候可以这样使用
//相当于在有限的资源情况下,让合理的应用
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(2);
System.out.println(Thread.currentThread().getName() + "离开车位");
}catch (InterruptedException e){
e.printStackTrace();
}finally {
//释放
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
输出结果:
1抢到车位
3抢到车位
2抢到车位
3离开车位
1离开车位
6抢到车位
4抢到车位
2离开车位
5抢到车位
4离开车位
5离开车位
6离开车位