2

我可以看到如何在Java中实现“标准”Semaphore类。但是,我不知道如何在Java中实现二进制信号量类。这种实现如何工作?我应该何时调用wake和notify方法来唤醒和停止信号量上的线程? 我明白什么是二进制信号量,但我不知道如何对它们进行编码。如何在Java中实现二进制信号量类?

编辑注:意识到我说“BINARY”信号量类。标准的Semaphore类我已经做了,我知道它是正确的,所以标准的Semaphore类对我不感兴趣。

+0

你有没有尝试过;以现有信号灯类的源代码,它会如何表现,如果它是只需要1。 – Scorpion

+0

许可你看了(例如维基百科)的定义(二进制)信号量?你能解释为什么给出的答案(特别是Vikas的答案或亚历山大的更广泛的答案)是不够的?否则,你可以尝试解释用例(为了什么*目的*你需要二进制信号量/互斥量吗?) –

回答

3

我想你说的是互斥锁(或互斥锁)。如果是这样,你可以使用内部锁。这种在Java中的行为锁的互斥体,这意味着最多只有一个线程可以拥有锁:

synchronized (lock) { 
    // Access or modify shared state guarded by lock 
} 

如果锁是一个模拟对象,仅用于锁定使用。


编辑:

这是给你一个实现 - 它使用的零值表示未锁定状态非再进入的互斥锁类,以及一个代表锁定状态。

class Mutex implements Lock, java.io.Serializable { 

    // Our internal helper class 
    private static class Sync extends AbstractQueuedSynchronizer { 
     // Report whether in locked state 
     protected boolean isHeldExclusively() { 
     return getState() == 1; 
     } 

     // Acquire the lock if state is zero 
     public boolean tryAcquire(int acquires) { 
     assert acquires == 1; // Otherwise unused 
     if (compareAndSetState(0, 1)) { 
      setExclusiveOwnerThread(Thread.currentThread()); 
      return true; 
     } 
     return false; 
     } 

     // Release the lock by setting state to zero 
     protected boolean tryRelease(int releases) { 
     assert releases == 1; // Otherwise unused 
     if (getState() == 0) throw new IllegalMonitorStateException(); 
     setExclusiveOwnerThread(null); 
     setState(0); 
     return true; 
     } 

     // Provide a Condition 
     Condition newCondition() { return new ConditionObject(); } 

     // Deserialize properly 
     private void readObject(ObjectInputStream s) 
      throws IOException, ClassNotFoundException { 
     s.defaultReadObject(); 
     setState(0); // reset to unlocked state 
     } 
    } 

    // The sync object does all the hard work. We just forward to it. 
    private final Sync sync = new Sync(); 

    public void lock()    { sync.acquire(1); } 
    public boolean tryLock()   { return sync.tryAcquire(1); } 
    public void unlock()    { sync.release(1); } 
    public Condition newCondition() { return sync.newCondition(); } 
    public boolean isLocked()   { return sync.isHeldExclusively(); } 
    public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } 
    public void lockInterruptibly() throws InterruptedException { 
     sync.acquireInterruptibly(1); 
    } 
    public boolean tryLock(long timeout, TimeUnit unit) 
     throws InterruptedException { 
     return sync.tryAcquireNanos(1, unit.toNanos(timeout)); 
    } 
    } 

如果你需要知道你应该在哪里叫wait()notify(),看看sun.misc.Unsafe#park()。 ( - LockSupport < - 不安全的AbstractQueuedSynchronizer <)它的java.util.concurrent.locks包内使用。

希望这会有所帮助。

+0

你所说的是我应该放什么东西在二进制信号量的类。我已经知道了我应该做的,在某些时候,但我不知道我应该在哪里呼叫通知和w ait电话。 – Victor

+0

你不需要深入研究这样的细节(但是如果你愿意,可以看看'sun.misc.Unsafe'类,就像我在文章中提到的那样)。您可以通过派生的便利实现来实现您的目标。 – surlac

0

你可以看看的Java实现Semaphore类的源代码(或者直接用它?)

+0

我需要二进制信号量而不是那个。 – Victor

2

这里是直接从Java site

并发实用程序库,由Doug Lea领导的JSR-166是一个 专门发布的J2SE 5.0平台中的流行并发程序包。它提供了强大的高级线程结构,其中包括执行程序,它们是线程任务框架,线程安全的 队列,定时器,锁(包括原子的),以及其他 同步原语。

一个这样的锁是众所周知的信号量。信号量可以用于 ,与现在使用等待的方式相同,用于限制对代码块的访问。信号量更加灵活,并且还可以允许多个并发线程访问,并允许您在 获取它之前测试锁。以下示例仅使用一个信号量,也称为二进制信号量,即 。有关更多信息,请参阅java.util.concurrent包中的 。

final private Semaphore s= new Semaphore(1, true); 

    s.acquireUninterruptibly(); //for non-blocking version use s.acquire() 

try {  
    balance=balance+10; //protected value 
} finally { 
    s.release(); //return semaphore token 
} 

我认为,采用更高级别的摘要,例如Semaphore类的全部原因是,你不必叫低水平wait/notify

1

是的,你可以。具有单一许可证的信号量是二进制信号量。他们控制对单一资源的访问。他们可以被看作是某种互斥/锁。

Semaphore binarySemaphore = new Semaphore(1); 
+0

它没有帮助,我需要一个二进制信号类,而不是标准的。 – Victor

+0

如果它只有一个许可证,它**是**二进制信号量。您的评论好像是说“这车不适合的:它可以上升到180公里/小时,而我需要去在90公里每小时 –

+0

可以扩展标准信号和下面创建自己的二进制信号类。 公共类BinarySemaphore延伸旗语{ BinarySemaphore(){ 超级(1);} } – Drona

3

下面是一个简单的实现我做了一个二进制信号:

public class BinarySemaphore { 

    private final Semaphore countingSemaphore; 

    public BinarySemaphore(boolean available) { 
     if (available) { 
      countingSemaphore = new Semaphore(1, true); 
     } else { 
      countingSemaphore = new Semaphore(0, true); 
     } 
    } 

    public void acquire() throws InterruptedException { 
     countingSemaphore.acquire(); 
    } 

    public synchronized void release() { 
     if (countingSemaphore.availablePermits() != 1) { 
      countingSemaphore.release(); 
     } 
    } 
} 

该实现二进制信号,你不能用计数信号,只有有一个许可证获得一个属性 - 多个呼叫释放仍将只留下一个资源。这个属性被提到here

+0

这是不安全的 - 只有release()是同步的,所以如果acquire并发运行释放,在if(countingSemaphore.availablePermits()!= 1)之后,以及调用释放之前,最终可能会出现意外的行为。此外,使获取同步不会工作,因为锁然后锁定,停止释放二进制信号量,停止应用程序。 –

+0

@SamHeather我只是想着你说的话,如果非同步方法获取开始就像你在!= 1检查后说的那样,将没有可用的槽,并且内部的acquire-call会停止,并且线程会等待,上下文切换,另一个释放线程可以继续调用'countingSemaphore.release();' 只是想,如果这将是一个问题吗?我认为所有可能的请求线程都会卡在内核'countingSemaphore.acquire();'-call。你不这么认为吗? 同步'release()' - 方法只是避免了太多的空闲插槽。 – Dunstkreis

0

我有我自己的实施二进制信号在Java中的。

import java.util.concurrent.Semaphore; 
import java.util.concurrent.TimeUnit; 

/** 
* A binary semaphore extending from the Java implementation {@link Semaphore}. 
* <p> 
* This semaphore acts similar to a mutex where only one permit is acquirable. Attempts to acquire or release more than one permit 
* are forbidden. 
* <p> 
* Has in {@link Semaphore}, there is no requirement that a thread that releases a permit must have acquired that permit. However, 
* no matter how many times a permit is released, only one permit can be acquired at a time. It is advised that the program flow 
* is such that the thread making the acquiring is the same thread making the release, otherwise you may end up having threads 
* constantly releasing this semaphore, thus rendering it ineffective. 
* 
* @author Pedro Domingues 
*/ 
public final class BinarySemaphore extends Semaphore { 

    private static final long serialVersionUID = -927596707339500451L; 

    private final Object lock = new Object(); 

    /** 
    * Creates a {@code Semaphore} with the given number of permits between 0 and 1, and the given fairness setting. 
    * 
    * @param startReleased 
    *   <code>true</code> if this semaphore starts with 1 permit or <code>false</code> to start with 0 permits. 
    * @param fairMode 
    *   {@code true} if this semaphore will guarantee first-in first-out granting of permits under contention, else 
    *   {@code false} 
    */ 
    public BinarySemaphore(boolean startReleased, boolean fairMode) { 
     super((startReleased ? 1 : 0), fairMode); 
    } 

    @Override 
    public void acquire(int permits) throws InterruptedException { 
     if (permits > 1) 
      throw new UnsupportedOperationException("Cannot acquire more than one permit!"); 
     else 
      super.acquire(permits); 
    } 

    @Override 
    public void acquireUninterruptibly(int permits) { 
     if (permits > 1) 
      throw new UnsupportedOperationException("Cannot acquire more than one permit!"); 
     else 
      super.acquireUninterruptibly(permits); 
    } 

    @Override 
    public void release() { 
     synchronized (lock) { 
      if (this.availablePermits() == 0) 
       super.release(); 
     } 
    } 

    @Override 
    public void release(int permits) { 
     if (permits > 1) 
      throw new UnsupportedOperationException("Cannot release more than one permit!"); 
     else 
      this.release(); 
    } 

    @Override 
    public boolean tryAcquire(int permits) { 
     if (permits > 1) 
      throw new UnsupportedOperationException("Cannot acquire more than one permit!"); 
     else 
      return super.tryAcquire(permits); 
    } 

    @Override 
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { 
     if (permits > 1) 
      throw new UnsupportedOperationException("Cannot release more than one permit!"); 
     else 
      return super.tryAcquire(permits, timeout, unit); 
    } 
} 

告诉我,如果你发现代码中有任何错误,但到目前为止,它总是正常工作! :)

0

我宁愿使用Lock

除了命名匹配,Java的信号灯是没有办法实现BinarySemaphore,并使用对象等待/通知或同步是非常原始。

相反,Lock类提供的锁定语义与Semaphore锁定/解锁(与Semaphore的获取/释放相比)几乎相同,但它专门用于解决临界区域功能,只需要一个线程立即进入。

值得注意的锁还提供感谢超时语义尝试tryLock方法。