当通过它的线程量小于屏障限制时,屏障(例如 CyclicBarrier)是否会导致死锁?

Does barrier (e.g. CyclicBarrier) cause deadlock when the amount of thread passed it is smaller than the barrier limit?

当运行以下代码时,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 个启动的 线程 正在等待第三个三分之一来解决这个 barrier。但是,根据 CyclicBarrier 的 Java API 文档,CyclicBarrier

A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point

我对他们如何 "wait for each other"

感到困惑

问题:"wait for each other"是否意味着循环等待?如果是这样,如何?严格来说,这是死锁情况吗?

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

但最终结果与死锁非常相似,一开始可能会造成混淆。

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

但是这与死锁之间的主要区别在于如何解决它们:线程太少的循环屏障将通过更多线程到达来解决,在死锁中,唯一的 "resolution" 就是杀死一个线程已经在等待的线程数。

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

  1. 屏障维护对 await().
  2. 的调用记录
  3. 调用 await() 时,代码块(该方法不会 return),但屏障会增加其计数。
  4. 当计数达到构造时给定的 parties 值时,计数将被重置,并且在对 await() 的调用中被阻塞的所有线程都将被释放(即方法 returns).

因此,在您的情况下,对 await() 的调用不会 return 直到发生第三次调用,因此您的 2 个现有线程实际上被卡住了。这在技术上不是死锁,因为它可以很容易地摆脱(通过再次调用 await())。

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

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

each process must be waiting for a resource which is being held by another process, which in turn is waiting for the first process to release the resource. In general, there is a set of waiting processes, P = {P1, P2, …, PN}, such that P1 is waiting for a resource held by P2, P2 is waiting for a resource held by P3 and so on until PN is waiting for a resource held by P1.

您有一组进程 P1 和 P2。他们正在等待某事,但他们并不是在等待 P3,因为不存在这样的过程。所以这不是死锁。

也不满足以下条件:

Hold and wait or resource holding: a process is currently holding at least one resource and requesting additional resources which are being held by other processes.

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