Binary Semaphore vs ReentrantLock

时间:2013-07-16 17:47:39

标签: java multithreading semaphore

我一直在努力了解Reentrant锁和信号量(重入锁定与释放/解锁机制的嵌套)。

似乎有一个信号量要求你编写一个更彻底测试的应用程序,因为release()方法不会检查释放许可证的线程是否实际上持有它。当我测试我的测试代码时,我发现这可能随后增加超出初始限制的许可数量。另一方面,如果一个线程在调用unlock方法时没有持有重入锁,我们会得到一个IllegalMonitorException。

所以说没有真正的理由拥有二进制信号量是正确的,因为二进制信号量可以做的所有事情也可以由ReentrantLock完成。如果我们使用二进制信号量,我们必须检查整个方法调用堆栈以查看之前是否获得了许可证(如果有可能进行后续获取,它也会被释放 - 如果某个版本没有继续获取它可能会阻止它等等)。此外,由于重入锁也为每个对象提供一个锁,所以更喜欢将重入锁定为二进制信号量并不总是更好吗?

我在这里查了一篇文章,讨论二进制信号量和互斥量之间的区别,但有没有像Java中的互斥量这样的东西?

谢谢, 陈。

P.S - 我在另一个论坛(http://www.coderanch.com/t/615796/threads/java/reason-prefer-binary-Semaphore-Reentrant)发布了这个问题,但我还没有收到回复。我想我也会在这里发布,看看能得到什么。

3 个答案:

答案 0 :(得分:33)

  

没有任何理由可以将二进制信号量作为a的所有内容   二进制信号量可以做的也可以通过ReentrantLock

来完成

如果您只需要可重入互斥,那么是的,没有理由在ReentrantLock上使用二进制信号量。如果由于任何原因您需要非所有权释放语义,那么显然信号量是您唯一的选择。

  

此外,由于重入锁也为每个对象提供一个锁,因此不是   总是更喜欢将重入锁定转换为二进制信号量?

这取决于需要。如前所述,如果您需要一个简单的互斥锁,那么就不要选择信号量。如果多个线程(但数量有限)可以进入临界区,则可以通过线程限制或信号量来执行此操作。

  

我在这里查了一篇关于a之间差异的帖子   二进制信号量和互斥量,但有一个像互斥量的东西   爪哇?

ReentrantLocksynchronized是Java中互斥体的示例。

答案 1 :(得分:6)

我不会解释重入锁定,因为John已经在上面给出了一个很好的解释,并且它是java中的互斥锁示例以及Synchronized关键字。

但是,如果出于任何原因,您希望更好地控制锁定机制,Semaphore可以变得方便。这意味着,您的代码将不得不继续负责调用acquire()和调用release()的人,因为Semaphore本质上是盲目的,所有它关心的是许可变得可用。

使用java自己的互斥体实现的另一种方法是LockSupport。它的工作方式有点像信号量,但是在许可证上有一个超时,使用park()函数,并且一次只支持一个许可证,不像支持多个信号量的信号量。

答案 2 :(得分:0)

信号量和可重入锁之间有一些细微差别。

  • 信号量可能被另一个线程释放。 Semaphore的javadoc指出,这种行为在死锁恢复等某些特殊情况下可能很有用。因此,它应该是一个真正的专业化上下文。
  • 二进制信号量也不可重入。您不能在同一线程中第二次获取二进制信号量。它将导致死锁(线程本身具有死锁!),您可能需要一些已经提到的死锁恢复方法