【问题标题】: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的实现方式

标签: java multithreading concurrency barrier


【解决方案1】:

您可以将CyclicBarrier 视为根本不了解线程。可以这样想:

  1. 屏障保持对await() 的调用记录。
  2. await() 被调用时,代码阻塞(方法不返回),但屏障增加了它的计数。
  3. 当计数达到构造时给定的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 没错。它只是相关的,因为它是问题中混淆的根源之一。
      猜你喜欢
      • 2018-10-11
      • 1970-01-01
      • 2012-01-27
      • 2014-05-11
      • 2016-01-26
      • 2012-09-08
      • 2021-08-10
      • 1970-01-01
      • 2022-01-02
      相关资源
      最近更新 更多