问二十三:说说闭锁、栅栏、信号量是什么?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18657175/article/details/89784663

CountDownLatch的作用与使用场景:

作用:允许一个或多个线程等待,直到其他线程的一组事件完成(是一次性对象,一旦进入终止状态就不能被重置)

原理:

CountDownLatch是一种闭锁的实现,它可以使一个或多个线程等待一组事件发生

闭锁状态包括一个计数器,初始化为一个正数,用来表示需要等待的事件数量

countDown()递减计数器,表示有一个事件巳经发生

await()等待计数器达到零,这表示所有需要等待的事件都已经发生。如果计数器的值非零,那么 await会一直阻塞直到计数器为零,或者等待中的线程中断,或者等待超时

使用场景: 

1、确保某个服务在其依赖的所有服务都启动后再进行启动

2、确保某个计算在其需要的所有资源都进行初始化后才继续执行。如:统计一组线程所需要使用的时间,FutureTask的get()

3、等待某个操作的所有参与者都就绪再继续执行操作。如:王者荣耀的加载界面,如果将每个玩家都看做一条线程,每条线程的执行速度都不同,那么只有10名玩家都加载到100%时才开始游戏

实际操作:

附:

1、FutureTask也可用作闭锁,在Executor框架中表示异步任务,此外还可以用作表示一些时间较长的计算,这些计算可以在使用计算结果之前启动

2、如果直接使用await()方法,那么当某个事件陷入无限期等待状态时,await()方法也会一直等待,可以使用await(long timeout, TimeUnit unit)来进行限期等待

CyclicBarrier的作用与使用场景:

作用:类似于闭锁,能够阻塞一组线程直到某个事件发生,所有的线程必须同时到达栅栏位置才能继续执行。闭锁用于等待事件(即一个线程中可能出现多个事件),而栅栏用于等待其他线程

原理:CyclicBarrier可以使一定数量的参与方反复地在栅栏位置汇集,当线程到达栅栏位置时将调用await(),这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达了栅栏位置,那么栅栏将打开,此时所有线程都被释放,而栅栏将被重置以便下次使用。如果对await()的调用超时,或者await阻塞的线程被中断,那么栅栏就被认为是打破了,所有阻塞的await调用都将终止并抛出BrokenBarrierException。如果成功地通过栅栏,那么await将为每个线程返回一个唯一的到达索引号,我们可以利用这些索引来“选举”产生一个领导线程,并在下一次迭代中由该领导线程执行一些特殊的工作。CyclicBarrier还可以使你将一个栅栏操作传递给构造函数,这是一个Runnable,当成功通过栅栏时会(在一个子任务线程中)执行它,但在阻塞线程被释放之前是不能执行的。

使用场景:在并行迭代算法中非常有用:这种算法通常将一个问题拆分成一系列相互独立的子问题

实际操作:

代码流程:等待员工到达会议室->Boss发言->员工一起发言讨论->Boss对各员工进行总结->Boss发言结束会议(体现CyclicBarrier可重用,能够等待一组线程到达,然后一起做某一件事情)

附:

另一种形式的栅栏是Exchanger,它是一种两方(Two-Party)栅栏,各方在栅栏位置上交换数据。当两方执行不对称的操作时,Exchanger会非常有用,例如当一个线程向缓冲区写入数据,而另一个线程从缓冲区中读取数据。这些线程可以使用Exchanger来汇合,并将满的缓冲区与空的缓冲区交换。当两个线程通过Exchanger交换对象时,这种交换就把这两个对象安全地发布给另一方。

数据交换的时机取决于应用程序的响应需求。最简单的方案是,当缓冲区被填满时,由填充任务进行交换,当缓冲区为空时,由清空任务进行交换。这样会把需要交换的次数降至最低,但如果新数据的到达率不可预测,那么一些数据的处理过程就将延迟。另一个方法是,不仅当缓冲被填满时进行交换,并且当缓冲被填充到一定程度并保持一定时间后,也进行交换。

Semaphore

作用:用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量,还可以用来实现某种资源池,或者对容器施加边界。

原理:Semaphore中管理着一组虚拟的许可(permit),许可的初始数量可通过构造函数来指定。在执行操作时可以首先获得许可(只要还有剩余的许可),并在使用以后释放许可。如果没有许可,那么acquire将阻塞直到有许可(或者直到被中断或者操作超时),release方法将返回一个许可给信号量。

计算信号量的一种简化形式是二值信号量,即初始值为1的Semaphore。

二值信号量可以用做互斥体(mutex),并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。

Semaphore可以用于实现资源池,例如数据库连接池。

我们可以构造一个固定长度的资源池,当池为空时,请求资源将会失败,但你真正希望看到的行为是阻塞而不是失败,并且当池非空时解除阻塞。如果将Semaphore的计数值初始化为池的大小,并在从池中获取一个资源之前首先调用acquire方法获取一个许可,在将资源返回给池之后调用release释放许可,那么acquire将一直阻塞直到资源池不为空。(在构造阻塞对象池时,一种更简单的方法是使用BlockingQueue来保存池的资源。)

使用场景:即作用

实际操作:

猜你喜欢

转载自blog.csdn.net/qq_18657175/article/details/89784663