Java Semaphore

Semaphore Introduction

Semaphore is a synchronization primitive that can be used to ensure that only one thread can access a shared resource at any point of time. Semaphore guards critical sections of the code by providing the necessary signalling and prevents any race conditions. Semaphore controls access to shared resources by using counters. If the value of semaphore i.e. counter is greater than zero then it indicates resources are available and a thread can access the shared resource. If the value of semaphore is zero then no resources are available and access is denied.

Semaphores that  allow any arbitrary value for the counter is called counting semaphores. Semaphores that allow only values 0 and 1 are called binary semaphores.

Java Semaphore Class

Java supports Semaphore synchronization object that can be used to implement semaphore. Some of the key APIs of Semaphore class are listed below.

  • Semaphore(int permits) – Constructor that creates a semaphore with the given number of permits.
  • Semaphore(int permits, boolean fair) – Constructor that creates a semaphore with the given number of permits and fairness. If fairness is true it is ensured that waiting threads are granted a permit in the order they requested access.
  • void acquire() – Acquires one permit. If permit is not granted at the time of call then the invoking thread is suspended.
  • void acquire(int permits) – Acquires the specified number of permits.
  • void release() – Release a permit back to the semaphore.
  • void release(int permits) – Releases specified number of permits back to the semaphore.

Java Semaphore Example

In this example, we create a shared resource i.e. count. There is a producer thread which increments the count. There is a consumer thread which decrements the count. We create a semaphore to synchronize the producer and consumer. Both the threads acquire a permit from the semaphore before executing the critical section. Once completed the thread releases the permit back to the semaphore.

package com.sourcetricks.semaphore;import java.util.concurrent.Semaphore;public class SemaphoreExample {// Shared resources to be guardedprivate static int count = 0;// Producer thread. Counts up the resource.private static class ProducerThread implements Runnable {private Semaphore s = null;ProducerThread(Semaphore s) {this.s = s;}@Overridepublic void run() {try {System.out.println("Producer requesting permit");s.acquire();System.out.println("Producer gets permit");for ( int i = 0; i < 5; i++ ) {count = count + 1;System.out.println("Counting up");}Thread.sleep(5000);System.out.println("Producer releases permit");s.release();} catch (InterruptedException e) {e.printStackTrace();}}}// Consumer thread. Counts down the resource.private static class ConsumerThread implements Runnable {private Semaphore s = null;ConsumerThread(Semaphore s) {this.s = s;}@Overridepublic void run() {try {System.out.println("Consumer requesting permit");s.acquire();System.out.println("Consumer gets permit");for ( int i = 0; i < 5; i++ ) {count = count - 1;System.out.println("Counting down");}System.out.println("Consumer releases permit");s.release();} catch (InterruptedException e) {e.printStackTrace();}}}// Main programpublic static void main(String[] args) {Semaphore semaphore = new Semaphore(1);Thread t1 = new Thread(new ProducerThread(semaphore));Thread t2 = new Thread(new ConsumerThread(semaphore));t1.start();t2.start();}}

This program produces the following output.

Producer requesting permitConsumer requesting permitProducer gets permitCounting upCounting upCounting upCounting upCounting upProducer releases permitConsumer gets permitCounting downCounting downCounting downCounting downCounting downConsumer releases permit

Read other concurrency tutorials from Java Tutorials page.