Java Semaphore example

Semaphore can be used to limit the amount of concurrent threads and essentially, this class maintains a set of permits.

acquire() takes a permit from the semaphore and release() returns the permit back to the semaphore.  In the event of absence of permits, acuire() will block until one is available

Semaphore is used to control access to the specific resources.

java-featured-image

Workflow 

Semaphore is set with a count value. Then threads try to acquire permit and if the count is 0 or less than 0, the thread will be blocked and it will be waiting for the next permit (if there is any). This will be kept doing until count is greater than 0. If it is, the semaphore will provide access to resources to the thread. Thread will then release the permit and count will be incremented by 1.

Constructors

  1. Semaphore(int permits): creates a Semaphore with the given number of permits and nonfair fairness setting
  2. Semaphore(int permits, boolean fair): creates a Semaphore with the given number of permits and the given fairness setting

Main Methods

  1. void acquire(): acquires a permit from the current semaphore, blocking until one is available, or the thread is interrupted.
  2. void acquire(int permits): acquires the specified nubmer of permits from the current semaphore, blocking until all are available or the thread is interrupted.
  3. int availablePermites(): returns the current number of permits available in the current semaphore

To view all the methods, click here. You will be redirected to the official Oracle documentation.

Semaphore can be used to lock access to a specific resource. Each thread has to ask for a “permission”, hence the need of calling the method acquire() before accessing the resource. When the thread no longer needs the resource, it has to call release() to release the lock.

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
	
	
	public static void main(String[] args) throws Exception {	
		Semaphore semExample = new Semaphore(1);
		System.out.println("Available permits: " + semExample.availablePermits());
		
		semExample.release();
		
		System.out.println("Available permits: " + semExample.availablePermits());
	
		semExample.acquire();
		
		System.out.println("Available permits: " + semExample.availablePermits());
		
		semExample.acquire();
		
		System.out.println("Available permits: " + semExample.availablePermits());
		
		semExample.acquire();
		System.out.println("Available permits: " + semExample.availablePermits());
	}
}





Output

Available permits: 1
Available permits: 2
Available permits: 1
Available permits: 0

What you can see from the above example is that when you call release(), you are adding a permit to the Semaphore instance. When you are calling acquire(), you are removing a permit(). When there are no permits and you call acquire, it will be waiting until a permit has been released, hence the last print statement won’t ever get executed in the example above.

When you have 1 permit and then you have an acquire() call and straight after it a release() call, it is called a lock. 

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {

    Semaphore thread = new Semaphore(1);
  
    public static void main(String args[]) {
        final SemaphoreDemo test = new SemaphoreDemo();
        new Thread(){
            @Override
            public void run(){
              test.mutualExclusion(); 
            }
        }.start();
      
        new Thread(){
            @Override
            public void run(){
              test.mutualExclusion(); 
            }
        }.start();
      
    }
  
    private void mutualExclusion() {
        try {
        	System.out.println(Thread.currentThread().getName() + " is waiting to acquire a permit.");
        	thread.acquire();
            System.out.println("Permit has been acquired to " + Thread.currentThread().getName());
            Thread.sleep(1000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
        	System.out.println(Thread.currentThread().getName() + " is releasing the permit...");
            thread.release();
            System.out.println("Released.");
        }
    } 
  
}

Output

Thread-0 is waiting to acquire a permit.
Permit has been acquired to Thread-0
Thread-1 is waiting to acquire a permit.
Thread-0 is releasing the permit...
Released.
Permit has been acquired to Thread-1
Thread-1 is releasing the permit...
Released.

As you can see from the output after an acquisition has been permitted to Thread-0, thread 1 started waiting to acquire a permit for itself but it (thread-1) only got it when thread-0 released its permit.

Leave a Reply

avatar