这三者都是juc(jdk中并发的包)中的概念。简单说
- CountDownLatch:计数器
- CyclicBarrier 条件满足器
- Semaphore 信号灯
下面一个个仔细的说:
CountDownLatch
这个之前我学JUC的时候已经记录过了,这里就当复习了,其实这个可以算是计数器,也可以算是门闩。当门里的人都走了,才可以去锁门!
下面是一个情景demo:
屋子里有6个人,用六个线程来表示,而main线程充当锁门的那个人。在没有任何操作的情况下的代码:
其实这个代码因为没有任何处理所以逻辑比较简单,那就是锁门和出门同时进行,把人锁门里是一个正常事件了,这样肯定是不行的。
但是!!这个时候不会有小机灵鬼说等一等再锁门吧?比如main线程睡个几秒啥的。表面上看上面的程序是可以正常跑了,但是仔细想想,这几个线程什么时候出门是不固定的啊。万一睡个几小时再出门呢?所以这个方法绝对是不行了。
这个时候计数器CountDownLatch就要起作用啦!
这个计数器的用法也很简单,大概的思路就是初始的时候设置倒计数。每次调用countDown()的时候计数器会减一。如果调用了await方法以后,直到计数器数字为0才能往下走。如下代码:
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(6);
for(int i = 0;i<6;i++) {
new Thread(()-> {
System.out.println(Thread.currentThread().getName()+"离开了!");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
try {
countDownLatch.await();
System.out.println("锁门了!");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
上面代码的重点其实就两个:一个countDownLatch.countDown(); 一个countDownLatch.await();
这里要注意一定要把countDownLatch.countDown()放在打印语句下面。不然可能会出现先归零锁门,再输出离开了的打印语句。
CyclicBarrier
这个和计数器正好相反,而是一个加法。从0增加到给定值,类似于七颗龙珠召唤神龙一样。同样一个小情景:七个人要开会。人到齐了才能开始。否则就要等人。
下面依然代码做demo:
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("人齐了,可以开会了!");
});
for(int i = 0;i<7;i++) {
new Thread(()-> {
System.out.println(Thread.currentThread().getName()+"来了!");
try {
cyclicBarrier.await();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
这里依然两个小重点:一个是 CyclicBarrier的函数式接口中,写满足条件的逻辑。
一个是cyclicBarrier.await();方法代表加入这个cyclicBarrier的等待队列。
当等待数目达到要求,就可以执行满足条件的逻辑代码了。
Semaphore
这个是信号灯,是可伸缩可变化的。据说小米的秒杀系统中大量使用这个哟!
使用场景大概是多个线程抢多个资源。信号灯主要用于两个目的:一个是用于多个共享资源的互斥使用。另一个用于并发线程数的控制。
Semaphore默认是非公平锁。
下面一个使用场景是停车位和车。默认初始3个停车位。7个车去抢,现在的代码demo:
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for(int i = 0;i<7;i++) {
new Thread(()-> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"抢到车位了!");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开了!");
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}finally {
}
},String.valueOf(i)).start();
}
}
这个信号灯的重点有三个:一个是默认的资源量(初始的时候设置的3).一个是占用资源:semaphore.acquire()。还有一个是释放资源:semaphore.release()。
这里信号灯牛就牛在不是单一的操作。而是可用可还的那种。
执行起来结果如下:
大家可以注意,同时最多三个车在停车位停着。但是其自动离开释放资源使得7个车最终都停成功了。不同于上面的计数器和cyclicBarrier的单向操作,这个是有借有还的。对于刻在用资源来讲信号灯是很实用的!
本篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利!
网友评论