Victor
Victor

Reputation: 1703

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.

Upvotes: 2

Views: 15967

Answers (8)

Mr.black
Mr.black

Reputation: 21

Maybe it's a good idea to use AtomicBoolean implement it. If it's not, please let me know.

import java.util.concurrent.atomic.AtomicBoolean;

public class BinarySemaphore {
    
    private final AtomicBoolean permit;
    
    public BinarySemaphore() {
        this(true);
    }
    
    /**
     * Creates a binary semaphore with a specified initial state
     */
    public BinarySemaphore(boolean permit) {
        this.permit = new AtomicBoolean(permit);
    }

    public void acquire() {
        boolean prev;
        do {
            prev = tryAcquire();
        } while (!prev);
    }

    public boolean tryAcquire() {
        return permit.compareAndSet(true, false);
    }

    /**
     * In any case, the permit was released
     */
    public void release() {
        permit.set(true);
    }

    public boolean available(){
        return permit.get();
    }
}

Upvotes: 1

Jaime Casero
Jaime Casero

Reputation: 421

I would rather use the Lock class

Besides the naming matching, Java Semaphore is no way to implement a BinarySemaphore, and using Object wait/notify or synchronize is quite raw.

Instead, the Lock class provides almost the same locking semantics as a Semaphore with its lock/unlock (versus acquire/release by Semaphore), but it is specifically targeted to solve critical section functionality, where just one thread is expected to enter at once.

Worth noting Lock also provide try with timeout semantics thanks to tryLock method.

Upvotes: 1

PedroD
PedroD

Reputation: 6023

I have my own implementation of a Binary Semaphore in 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);
    }
}

Tell me if you find any bug in the code please, but so far it always worked fine! :)

Upvotes: 1

DMan
DMan

Reputation: 289

Here is a simple implementation I did for a binary semaphore:

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

This implementation has one property of binary semaphores that you cannot get with counting semaphores that only have one permit - multiple calls to release will still leave just one resource available. This property is mentioned here.

Upvotes: 4

surlac
surlac

Reputation: 2961

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.

Upvotes: 4

Drona
Drona

Reputation: 7234

Yes, you can. A semaphore with a single permit is a binary semaphore. They control access to a single resource. They can be viewed as some kind of a mutex/lock.

Semaphore binarySemaphore = new Semaphore(1);

Upvotes: 3

Alexander Pogrebnyak
Alexander Pogrebnyak

Reputation: 45576

Here is straight from the Java site

The concurrency utility library, led by Doug Lea in JSR-166, is a special release of the popular concurrency package into the J2SE 5.0 platform. It provides powerful, high-level thread constructs, including executors, which are a thread task framework, thread safe queues, Timers, locks (including atomic ones), and other synchronization primitives.

One such lock is the well known semaphore. A semaphore can be used in the same way that wait is used now, to restrict access to a block of code. Semaphores are more flexible and can also allow a number of concurrent threads access, as well as allow you to test a lock before acquiring it. The following example uses just one semaphore, also known as a binary semaphore. See the java.util.concurrent package for more information.

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
}

I think, the whole reason of using higher-level abstracts such as Semaphore class is that you don't have to call low level wait/notify.

Upvotes: 2

Miquel
Miquel

Reputation: 15675

You could have a look at the source code for the Java implementation of the Semaphore class (or perhaps use it directly?)

Upvotes: 0

Related Questions