A Semaphore synchronizes access to a shared resource. With trivial synchronized blocks, only one thread can enter the critical section at a time,
with Semaphores there is no restriction. We can define the no. of threads accessing the shared source while initializing the Semaphore.
Semaphore controls the access to shared resource using a counter. When a thread asks for permit (using acquire() method of Semaphore), Semaphore
checks the counter, if counter is greater than zero, permit will be given to requesting thread,consequently thread will be allowed to
enter the critical section.
If counter is zero, calling thread will be suspended until some other thread releases the semaphore (using release() method of Semaphore).
Semaphore class has two constructors.
Semaphore(int permits, boolean fair)
First constructor allows us to set the number of permits. Think of counter here as permit. If we set the no. of permits to 2, the Semaphore
will have two permits which it can assign to any two threads.
If Semaphore has suspended some threads and any other thread releases the semaphore, it will pick a random thread from
suspended threads to start execution again. That’s not fair (why?). boolean fair in constructor will alternate this behaviour, if fair
is set to true threads will be resumed in order in which they were suspended.
acquire() / release()
acquire() acquires a permit from this semaphore, blocking until one is available, or the thread is interrupted. Read more here.
release() releases a permit, returning it to the semaphore.. Read more here.
Let’s create a simple program to understand Semaphores. We create two threads which will update a shared resource - a static counter. Each
thread will get permit before incrementing the resource and will release if afterwards.