Search code examples
javamultithreadingconcurrencysemaphoreconcurrent-programming

How to implement a Binary Semaphore Class in Java?


I can see how a "standard" Semaphore Class can be implemented in Java. However, I cant see how to implement a Binary Semaphore Class in Java. How does such implementation work? When should I call the wake and notify methods to wake and stop the threads that are on the semaphores? I understand what binary semaphores are, but I have no idea of how to code them.

Edit Note: Realize that I said "BINARY" Semaphore class. The standard Semaphore class I already did and I know its correct so the standard Semaphore Class does not interest me.


Solution

  • I think you're talking about mutex (or mutual exclusion locks). If so, you can use intrinsic locks. This kind of locks in Java act as mutexes, which means that at most one thread may own the lock:

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

    Where lock is a mock object, used only for locking.


    EDIT:

    Here is an implementation for you — non-reentrant mutual exclusion lock class that uses the value zero to represent the unlocked state, and one to represent the locked state.

    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));
        }
      }
    

    If you need to know where should you call wait() and notify(), have a look at sun.misc.Unsafe#park(). It is used within java.util.concurrent.locks package (AbstractQueuedSynchronizer <- LockSupport <- Unsafe).

    Hope this helps.