Understanding Java Semaphore Concurrency
Semaphore is a variable or abstract data type that controls the number of threads than can access some shared resource. This access to shared resource is controlled using permits.
Semaphore - Table Of Contents
Understanding Java Semaphore Java Semaphore - Print even and odd numbers using Threads Java Semaphore - Print numbers sequence using three Threads
What is a semaphore?
-
Semaphore is a term derived from ancient Greek words (sêma, "sign") and (-phoros, "bearing, bearer") meaning 'sign, bearing/bearer'.
- Semaphore is technique used to control access to a shared resource.
- It maintains a counter which specifies the number of resources available.
- When there is a request to access the process, the access is allowed only if the counter value is greater than zero. If the counter value is zero it indicates thatthe resource is not available and so cannot be accessed.
- So Semaphore acts as a doorkeeper who gaurds the shared resource. It grants access only if counter is available.
How does semaphore work?
- A semaphore acts as a limiter of available resource pool depth; for example, a semaphore with a capacity of 10 allows a maximum of 10 threads to acquire it at once, and any further threads that attempt to acquire it will block until one of the other threads releases it.
- This is somewhat different from ordinary mutual exclusion or monitor locking, which is typically used to prevent more than one thread from simultaneously modifying the same variables and causing inconsistent results or program state.
- So how does semaphore specify how many threads can simultaneously access it. This is specified using a permit.
If the permit value is greater than zero, semaphore allows a thread access to the shared resource.
If the permit value is zero or less than zero, the thread is put in waiting list. So in order to access the shared resource, the thread will need to be granted a permit from the semaphore.
Semaphore has the following constructors -
- Semaphore(int permits)
- Semaphore(int permits, boolean fair)
The Semaphore's provides following acquire methods-
-
void acquire( ) throws InterruptedException
This method checks the semaphore permit value. If it is greater than zero it acquires the permit and decrements the number of available permits by 1. If the semaphore value is zero or negative the thread is put in waiting list and stays there until some other thread calls release() method on this semaphore or some other thread interrupts the current thread.
-
void acquire(int permits) throws InterruptedException
This acquire method checks if the Semaphore permit value is greater than or equal to the permits provided as argument.If available and decrements the number of available permits by permits. If not available the threading requesting acquire is put in waiting list and stays there until some other thread calls release() method on this semaphore or some other thread interrupts the current thread.
-
void release( )
This Semaphore method releases permit to the shared resource and increases the number of available permits by 1. In order to release lock to the shared resource by calling the release() method it is not mandatory that the thread must have previously acquired permit by calling the acquire method.
-
void release(int permits )
This Semaphore method releases permits as specified in the method argument and increases the number of available permits by method argument permits. In order to release lock to the shared resource by calling the release(permits) method it is not mandatory that the thread must have previously acquired permit by calling the acquire method.
package com.javastructures; import java.util.concurrent.Semaphore; public class SemaphoreExample { public static void main(String args[]) { //create a semaphore with single permit Semaphore semaphore = new Semaphore(1); System.out.println("Created Semaphore with 1 permit"); //create a task which uses the above created semaphore Task1 task1 = new Task1(semaphore); Thread t1 = new Thread(task1, "Task1"); t1.start(); //create a task which uses the above created semaphore Task2 task2 = new Task2(semaphore); Thread t2 = new Thread(task2, "Task2"); t2.start(); } } class Task1 implements Runnable { Semaphore semaphore; public Task1(Semaphore semaphore) { this.semaphore = semaphore; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + " is waiting to acquire the permit"); //acquire a permit if available else wait for one to be available semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " has acquired the permit"); for (int i = 0; i < 5; i++) { System.out.println(i); Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " has released the permit"); //release the acquired permit semaphore.release(); } } class Task2 implements Runnable { Semaphore semaphore; public Task2(Semaphore semaphore) { this.semaphore = semaphore; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + " is waiting to acquire the permit"); //acquire a permit if available else wait for one to be available semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " has acquired the permit"); for (int i = 0; i < 5; i++) { System.out.println(i); Thread.sleep(500); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " has released the permit"); //release the acquired permit semaphore.release(); } }Run the program as a Java Application -