2013-03-28 18 views
4

如果你有一次只有一次人应该访问的资源,你可以使用大小为1的信号量,或者你可以只使用一个ReentrantLock实例?规模1的信号量是最好的选择?

使一个或另一个更好的决定的微妙差异是什么?

+2

为什么不'synchronized'? – NPE 2013-03-28 10:16:11

+2

我不认为会有任何 - 当'permit'设置为1时,2个API变得几乎相同。并且这两个实现都基于'AbstractQueuedSynchronizer',所以行为和性能应该接近相同。 – assylias 2013-03-28 10:16:13

回答

5

有差异:

  1. 信号灯可以由一个线程来获取和另一个线程释放。这样,一个线程可以发信号通知另一个线程。计数为1的信号也可用于互斥。另一方面,锁只用于相互排斥。
  2. 信号量不可重入。这意味着当许可证耗尽时,即使线程已被同一线程获取,线程也无法获取信号量。锁可以是可重入的。
1

Semaphore s很适合计数许可/发布,所以如果你有多个资源,Lock等。对你无能为力。但是如果你只有一种资源需要防范,那么它们已经足够好了。

+0

@Raif H绝对零差呢?只有我能想到的是,如果你不是100%确定它总是限制为1。 – 2013-03-28 10:18:08

+0

就像assylias所说的那样,它们(和'java.util.concurrent'中的许多其他)基于'AbstractQueuedSynchronizer',并将具有相同的性能特征。为你选择正确的语义。 – 2013-03-28 10:28:46

0

计数信号量示例:您有一个受保护的对象,并允许同时访问不超过五个线程的限制。在这种情况下,初始值为5的计数信号量就是数学拟合。 Downey's Little book of Semaphores是理解构造的最佳读物之一。

+1

虽然属实,但我不明白这是如何回答这个问题的。 – NPE 2013-03-28 10:24:05

0

虽然这是事实,这可能与两个​​完成,并且Semaphore你首先必须弄清楚你将如何使用这些资源。如果您使用​​这意味着你将不得不在同步观看主题:

public void run() { 
    // some code 
    synchronized (resource) { 
    // use resource 
    } 
} 

如果你不想让线程观看的(这在我看来是更好),在getter方法使用Semaphore资源:

public Resource acquireResource() { 
    // acquire semaphore 
    return resource; 
} 

public void releaseResource() { 
    // release semaphore 
} 

和线程只是做:

public void run() { 
    // some code 
    Resource resource = ResourceContainer.getResource(); 
    // do something with resource 
    releaseResource(); 
} 

您可以Object参数添加到这些方法只是比较如果同一个对象释放信号量。