当通过它的线程量小于屏障限制时,屏障(例如 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
本身根本不了解线程。可以这样想:
- 屏障维护对
await()
. 的调用记录
- 调用
await()
时,代码块(该方法不会 return),但屏障会增加其计数。
- 当计数达到构造时给定的
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.
(强调我的)。您没有任何进程持有任何资源,因为不存在第三个进程。
当运行以下代码时,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
本身根本不了解线程。可以这样想:
- 屏障维护对
await()
. 的调用记录
- 调用
await()
时,代码块(该方法不会 return),但屏障会增加其计数。 - 当计数达到构造时给定的
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.
(强调我的)。您没有任何进程持有任何资源,因为不存在第三个进程。