当通过的线程数量小于屏障限制时,屏障(例如 CyclicBarrier)是不是会导致死锁?
Posted
技术标签:
【中文标题】当通过的线程数量小于屏障限制时,屏障(例如 CyclicBarrier)是不是会导致死锁?【英文标题】:Does barrier (e.g. CyclicBarrier) cause deadlock when the amount of thread passed it is smaller than the barrier limit?当通过的线程数量小于屏障限制时,屏障(例如 CyclicBarrier)是否会导致死锁? 【发布时间】:2018-12-20 21:47:45 【问题描述】:运行以下代码时,2个启动线程将被CyclicBarrier
*对象锁定,无限等待第三个线程解锁
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class MainDeadlock
public static void main(String[] args) throws InterruptedException
final CyclicBarrier c = new CyclicBarrier(3);
Runnable r = () ->
try
c.await();
catch (InterruptedException | BrokenBarrierException e)
e.printStackTrace();
System.out.println("Run!");
;
new Thread(r).start();
new Thread(r).start();
所以 2 个启动的 线程 正在等待第三个线程来解决这个 障碍。但是,根据CyclicBarrier的Java API文档,CyclicBarrier
是
一种同步辅助工具,允许一组线程相互等待以达到共同的障碍点
我对他们如何“互相等待”感到困惑,
问题:“互相等待”是否意味着循环等待?如果是这样,怎么做?严格来说,这是一种僵局吗?
【问题讨论】:
我真的建议你去进一步阅读有关死锁的知识。这不是一个。同步辅助的使用不当会导致所有线程无限期地等待吗?是的。这和死锁一样吗?没有。 这个比较复杂,不知道CyclicBarrier
的实现方式
【参考方案1】:
您可以将CyclicBarrier
视为根本不了解线程。可以这样想:
-
屏障保持对
await()
的调用记录。
当await()
被调用时,代码阻塞(方法不返回),但屏障增加了它的计数。
当计数达到构造时给定的parties
值时,计数被重置,并且在调用await()
时被阻塞的所有线程都被释放(即方法返回)。
因此,在您的情况下,对 await()
的调用在第三次调用发生之前不会返回,因此您的 2 个现有线程实际上被卡住了。这在技术上并不是一个死锁,因为它可以很容易地摆脱(通过再次调用await()
)。
之所以称为循环是因为一旦计数被重置并且线程被释放,它就可以再次使用。一个典型的用法是将parties
设置为将在其上同步的线程数,并且这些线程都进入某种循环,由此屏障用于确保没有线程移动到下一次迭代,直到所有其他线程也已完成当前迭代。
【讨论】:
【参考方案2】:关于将情况视为死锁所需的循环等待条件,Wikipedia says:
每个进程都必须等待一个资源 另一个进程,它又在等待第一个进程 释放资源。一般来说,有一组等待进程, P = P1, P2, ..., PN,这样 P1 正在等待由 P2,P2 正在等待 P3 持有的资源,依此类推,直到 PN 等待 P1 持有的资源。
您有一组进程 P1 和 P2。他们正在等待某事,但他们没有等待 P3,因为不存在这样的进程。因此,这不是死锁。
也不满足以下条件:
等待或资源持有:一个进程当前持有 至少一项资源 并请求额外的资源 由其他进程持有。
(强调我的)。您没有任何进程持有任何资源,因为不存在第三个进程。
【讨论】:
【参考方案3】:从技术上讲,这不是死锁,因为已经在屏障处的两个线程没有相互阻塞,它们正在等待第三个永远不会到达的线程。
但最终结果与死锁非常相似,一开始可能会令人困惑。
措辞也有点令人困惑,因为从技术上讲,在具有限制 n
的循环障碍中,第一个 n-1
线程正在等待 nth
线程。
但这与死锁之间的主要区别在于您如何解决它们:线程太少的循环障碍将通过更多线程到达来解决,在死锁中,唯一的“解决方案”是已经杀死其中一个线程等待。
【讨论】:
最终结果相似并不真正相关(while (true);
具有相似的最终结果......),“死锁”有一个非常具体的定义,这并不满足它。
@Michael 没错。它只是相关的,因为它是问题中混淆的根源之一。以上是关于当通过的线程数量小于屏障限制时,屏障(例如 CyclicBarrier)是不是会导致死锁?的主要内容,如果未能解决你的问题,请参考以下文章