Java中用信号量获取、释放、再获取多个permit时是否有死锁?
Is there a deadlock when acquiring, releasing, and then acquiring multiple permits with semaphores in Java?
以下代码片段是 https://leetcode.com/problems/print-in-order/ 的解决方案,它使用单个信号量按顺序运行 printFirst.run()
、printSecond.run()
和 printThird.run()
。三个线程 A、B 和 C 调用函数。线程 A 将调用 first
,线程 B 将调用 second
,线程 C 将调用 third
.
我理解为什么 third
中需要 lock.acquire();
后跟 lock.release();
,而不是立即调用 lock.acquire(2);
,因为 Java 分配许可的方式到队列中的等待线程。调用 lock.acquire(2);
会造成死锁,因为没有任何东西可以释放足够的许可。
话虽这么说,但我不明白 lock.acquire();
后面跟着 lock.release();
是如何修复它的。
有人可以向我解释在 first
首先调用 lock.release()
然后 third
在 second
之前调用 lock.acquire(); lock.release(); lock.acquire(2);
的情况下会发生什么吗运行?这是否会导致死锁,就像调用 lock.acquire(2);
本身会导致死锁一样?这只是一种不太可能的情况,这就是它起作用的原因吗?
如有任何帮助,我们将不胜感激,谢谢!
class Foo {
private Semaphore lock = new Semaphore(0);
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
lock.release();
}
public void second(Runnable printSecond) throws InterruptedException {
lock.acquire();
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
lock.release(2);
}
public void third(Runnable printThird) throws InterruptedException {
lock.acquire();
lock.release();
lock.acquire(2);
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
}
}
我现在明白为什么这是正确的并且不会死锁了。
在third()
中的acquire(2)
之前有acquire()
和release()
意味着许可证的数量在获得时保证为1,这意味着second()
可以获取并且仍在进行中,或者 second()
已经调用了 acquire()
并且有 0 个许可,但这并不重要,因为 second()
即将 release(2)
,这将允许 third()
继续。
在 third()
中没有 acquire()
和 release()
,有可能 third()
会 acquire(2)
在其他线程中取得任何进展之前(即没有许可并且 second()
没有成功获得),这意味着 first()
中释放的许可将走向 third()
而第二个获得永远不会成功。
以下代码片段是 https://leetcode.com/problems/print-in-order/ 的解决方案,它使用单个信号量按顺序运行 printFirst.run()
、printSecond.run()
和 printThird.run()
。三个线程 A、B 和 C 调用函数。线程 A 将调用 first
,线程 B 将调用 second
,线程 C 将调用 third
.
我理解为什么 third
中需要 lock.acquire();
后跟 lock.release();
,而不是立即调用 lock.acquire(2);
,因为 Java 分配许可的方式到队列中的等待线程。调用 lock.acquire(2);
会造成死锁,因为没有任何东西可以释放足够的许可。
话虽这么说,但我不明白 lock.acquire();
后面跟着 lock.release();
是如何修复它的。
有人可以向我解释在 first
首先调用 lock.release()
然后 third
在 second
之前调用 lock.acquire(); lock.release(); lock.acquire(2);
的情况下会发生什么吗运行?这是否会导致死锁,就像调用 lock.acquire(2);
本身会导致死锁一样?这只是一种不太可能的情况,这就是它起作用的原因吗?
如有任何帮助,我们将不胜感激,谢谢!
class Foo {
private Semaphore lock = new Semaphore(0);
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
lock.release();
}
public void second(Runnable printSecond) throws InterruptedException {
lock.acquire();
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
lock.release(2);
}
public void third(Runnable printThird) throws InterruptedException {
lock.acquire();
lock.release();
lock.acquire(2);
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
}
}
我现在明白为什么这是正确的并且不会死锁了。
在third()
中的acquire(2)
之前有acquire()
和release()
意味着许可证的数量在获得时保证为1,这意味着second()
可以获取并且仍在进行中,或者 second()
已经调用了 acquire()
并且有 0 个许可,但这并不重要,因为 second()
即将 release(2)
,这将允许 third()
继续。
在 third()
中没有 acquire()
和 release()
,有可能 third()
会 acquire(2)
在其他线程中取得任何进展之前(即没有许可并且 second()
没有成功获得),这意味着 first()
中释放的许可将走向 third()
而第二个获得永远不会成功。