2011-02-22 31 views

回答

14

“更好”取决于上下文。根据詹姆斯麦克帕兰的说法,他们“同样强大”。我强烈建议观看his blog for a discussion on the differences

这里是一个快速指南,我发现:

信号灯

  • 可以在程序中任何地方使用,但不应该在一个显示器中使用
  • Wait()并不总是阻止调用者(即,当信号量计数器大于零时)。
  • Signal()要么释放阻塞的线程(如果有的话),要么增加信号量计数器。
  • 如果Signal()释放阻塞的线程,则调用者和释放的线程都会继续。

条件变量

  • 只能在监视器
  • Wait()始终阻塞调用者使用。
  • Signal()要么释放阻塞的线程,如果有的话,或者信号丢失,就好像它从不发生。
  • 如果Signal()释放阻塞的线程,调用者生成监视器(Hoare类型)或继续(Mesa类型)。只有一个调用者或已发布的线程可以继续,但不能同时有两个。

从这个信息:http://www.cs.mtu.edu/~shene/NSF-3/e-Book/MONITOR/sema-vs-monitor.html

一些有用的资源:

+3

这一般很有趣,但不直接适用于Java,因此稍有混淆。霍尔和梅萨监视器? – Air 2012-05-08 15:55:59

+0

是的,问题是针对Java问的,但答案与Java无关。 – t0r0X 2012-11-21 18:10:24

1

首先,你甲肝e决定使用哪个JDK。 仅提供线程的第一个Java版本。自Java Tiger(5.0)以来,引入了新类来处理并发。 特别提供了一个完整的包,其中包括java.util.concurrent

根据我的经验,我发现显示器更好,因为它们让代码更干净。而且,使用它们让代码更易于理解。他们通过实现接口的类通常实现的:由JDK提供的最有名的实现是的ReentrantLock类,它定义了一个普通的锁,以及特定的ReentrantReadWriteLock类,它提供写和/或读取锁定。

因此,使用锁来启用/禁用对共享对象(例如对象列表)的访问。

旗语对象是同步的用于协调和控制线(有在最新的JDK提供,如旗语的CyclicBarrierCountdownLatch,和类许多同步器)。例如,使用Semaphore,您可以将固定数量的标记释放到您的线程池中,并决定可以同时执行的操作数量。就我个人而言,我不喜欢这种方法,因为与Futures and Locks一起使用线程池可以以更清洁和更安全的方式获得相同的结果。

在本书中可以找到更多信息:“Java Concurrency in Practice”,在本IBM教程中:“Concurrency in JDK 5.0”。一些更好的例子可以找到here

3

确认,通过显示器我们的意思是旧的​​关键字。

第一个问题,你需要你的锁有柜台吗?

  1. 信号量可以有一个计数器大于一个。如果你需要保护N资源,信号量是最好的。轻松的决定。
  2. 如果您正在保护单个资源,这是信号量(1)和监视器同等适用的有趣情况。

J2SE 5.0 concurrency article在此给出了很好的建议。显示器是有限的,因为:

  • 没有办法从企图后退,以获取已持有的锁,或等待一段指定的时间后放弃或取消后锁定尝试一个中断。
  • 没有办法改变锁的语义,例如,在重入,读写保护或公平性方面。
  • 同步在方法和块中完成,因此限制使用严格的块结构锁定。换句话说,你不能在一种方法中获得锁,并在另一个方法中释放它。

因此,如果这些项目中的任何一项对您很重要 - 在超时后退出是一个很好的例子 - 那么请使用Semaphore。如果没有,显示器是好的。

7

如果你有头痛极小化后,更喜欢信号灯监视器(​​块/方法),无论你觉得锁定原语的真正的选择。 忽略关于信号量灵活性的学术讨论。你是在可靠性之后,而不是可配置性,不是吗?

人们经常声称监视器和信号灯是等价的(可以互相模拟),但是这种等价性比sometimes expected更加抽象和有用。 任何人谁可以正确模拟一个与另一个不需要任何回答这个问题了。

很明显,在允许同时进入块的线程数大于1的情况下,信号量是唯一的实际选择。因此,显示器的真正竞争对手是二进制信号量,即那些初始化为1的计数器,并且还包括那些您期望执行锁定以最终解锁信号量的线程的计算器。所以让我们仔细看看这些情况。

监视器和二进制信号量之间的根本区别是线程所有权。它具有很大的后果,那就是重入的能力。重入意味着已经拥有锁的线程可以重新获取它,而不是死锁。如果你的班级共享了你只是想用所有方法保护的状态,但却无法对这些方法如何相互呼叫提供永久的假设,这是一件大事。或者随着你的线程安全计划中发展的任何皮带和支架特征。

信号量永远不会重入,Java监视器总是可重入的。即使在单线程场景中,如果您需要锁定多个代码位置中的同一对象semaphores are prone to deadlocks,并且信号量的局限性只会在相对罕见的情况下带来任何好处,无论如何监视器并不是真正的选项。

线程所有权还大大降低了忘记锁定,忘记解锁或一个线程的活动掩盖另一个线程的活动的风险。在关联的Java语法中也存在显着的人机工程学差异。

另请注意this question;虽然它使用了不同的术语,但更好的答案在这里理解为“互斥体”,意味着Java“监视器”。