代码之家  ›  专栏  ›  技术社区  ›  Rui

当线程数量小于屏障限制时,屏障(例如cyclicbarrier)是否会导致死锁?

  •  0
  • Rui  · 技术社区  · 6 年前

    运行以下代码时,两个启动线程将被 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开始了 线 正在等待第三方解决此问题 障碍 . 但是,根据Java API文档 CyclicBarrier , 篱栅

    一种同步辅助工具,允许一组线程都等待对方到达一个公共的屏障点。

    我对他们的表现感到困惑 “等待对方” ,

    问题:“等待对方”是否意味着 循环等待 ?如果是,如何?严格来说,这是僵局吗?

    3 回复  |  直到 6 年前
        1
  •  1
  •   user31601    6 年前

    你可以想到 CyclicBarrier 因为根本不知道线程本身。这样想:

    1. 障碍物记录了 await() .
    2. 什么时候? 等待() 调用时,代码块(方法不返回),但屏障会增加其计数。
    3. 当计数达到 parties 在构造上给定的值,计数被重置,并且在调用中阻塞的所有线程 等待() 被释放(即方法返回)。

    所以,在你的情况下,打电话给 等待() 在第三次调用发生之前不会返回,因此您的2个现有线程实际上被卡住了。从技术上讲,这不是死锁,因为它可以很容易地解决(通过再次调用 等待() )

    它被称为 循环的 因为,一旦计数被重置并且线程被释放,它就可以再次使用。一个典型的用法是 当事人 设置要在其上同步的线程数,这些线程都会进入某种循环,通过这种循环,屏障可以确保在所有其他线程也完成当前迭代之前,没有线程移动到下一个迭代。

        2
  •  1
  •   Michael    6 年前

    关于被视为死锁的情况所需的循环等待条件, Wikipedia says :

    每个进程必须等待由 另一个进程,依次等待第一个进程 释放资源。一般来说,有一组等待过程, p=p1,p2,pn,这样p1正在等待由 p2,p2正在等待p3持有的资源,依此类推,直到pn 等待P1持有的资源。

    你有一组过程p1和p2。他们在等 某物 但他们并不等待P3,因为不存在这样的过程。所以这不是僵局。

    也不满足以下条件:

    等待或资源等待 : 进程当前保持在 至少一个资源 并请求其他资源 由其他流程持有。

    (强调我的)。您没有任何包含任何资源的进程,因为第三个进程不存在。

        3
  •  0
  •   biziclop    6 年前

    从技术上讲,这不是死锁,因为已经处于屏障处的两个线程没有被阻塞。 彼此之间 ,他们正在等待第三个从未到达的线程。

    但最终结果与死锁非常相似,一开始可能会令人困惑。

    措辞也有点混乱,因为从技术上讲,在有限制的循环屏障上 n 第一个 n-1 线程正在等待 nth 一个。

    但这和死锁的关键区别在于如何解决它们:线程太少的循环屏障将由更多的线程来解决,在死锁中,唯一的“解决方法”是杀死一个已经在等待的线程。