A Semaphore
controls access to shared resources by maintaining a count of permits.
The count of permit is passed to the Semaphore
during its initialization. Semaphore
doesn’t use any actual permit object and just depends on the count of the number available. If one wants to access the resource,
Semaphore
allows only if the internal count is greater than zero. A count of zero means, there is no resource available and someone holding the resource must release for the Semaphore
to allow further access. In this article, we look into an example of Semaphore and its APIs.
Semaphore Acquire and Release APIs
Let’s go through the APIs Semaphore
provides for acquiring and releasing the resource.
acquire()
We will use this to acquire resource from aSemaphore
. The internal count will get decremented by 1. If the counter is zero, the thread waits until the counter is non-zero.tryAcquire()
This is similar toacquire
, if no permit is available, instead of blocking, this method will return immediately with the valuefalse
. If able to acquire the resource, it will return with valuetrue
release()
Call this when you are done with the resource, it will increment the resource availability counter.
Semaphore Example
In our example, we use Semaphore
to control number of concurrent players in a gaming software.
For a user to join the game, its mandatory to acquire a permit from the Semaphore
. Class SoftwareGroupLicense
represents a group license. We pass the no. of concurrent players allowed. When a user exists the game, the permit is returned back to the Semaphore
. If all licenses are in use, the permit count would be zero in which case UsersExceededException
is thrown.
SoftwareGroupLicense:
package com.javarticles.concurrency; import java.util.concurrent.Semaphore; public class SoftwareGroupLicense { private Semaphore licenses; public SoftwareGroupLicense(int count) { licenses = new Semaphore(count); } public void join() { if (!licenses.tryAcquire()) { throw new UsersExceededException("All licenses are in use"); } System.out.println("Licenses left " + getAvailableLicenses()); } public void exit() { licenses.release(); System.out.println("Licenses left " + licenses.availablePermits()); } public int getAvailableLicenses() { return licenses.availablePermits(); } }
GamingUser:
package com.javarticles.concurrency; public class GamingUser { private SoftwareGroupLicense groupLicense; private String name; public GamingUser(String name, SoftwareGroupLicense groupLicense) { this.name = name; this.groupLicense = groupLicense; } public void join() { System.out.println(name + " joins"); groupLicense.join(); } public void exit() { System.out.println(name + " exists"); groupLicense.exit(); } }
UsersExceededException:
package com.javarticles.concurrency; public class UsersExceededException extends RuntimeException { public UsersExceededException(String msg) { super(msg); } }
Let’s test our Semaphore
. We create group license of five concurrent users. Next, we create a gaming user, pass the shared license object to it. When user joins, we call sempahore.tryAcquire()
. When user exists, we call semaphore.release()
.
SemaphoreExample:
package com.javarticles.concurrency; public class SemaphoreExample { public static void main(String[] args) { SoftwareGroupLicense groupLicense = new SoftwareGroupLicense(5); System.out.println("No. of licenses available: " + groupLicense.getAvailableLicenses()); GamingUser user1 = new GamingUser("User1" , groupLicense); user1.join(); GamingUser user2 = new GamingUser("User2" , groupLicense); user2.join(); GamingUser user3 = new GamingUser("User3" , groupLicense); user3.join(); GamingUser user4 = new GamingUser("User4" , groupLicense); user4.join(); GamingUser user5 = new GamingUser("User5" , groupLicense); user5.join(); GamingUser user6 = new GamingUser("User6" , groupLicense); try { user6.join(); } catch (UsersExceededException e) { System.out.println(e.getMessage()); user1.exit(); } } }
Output:
No. of licenses available: 5 User1 joins Licenses left 4 User2 joins Licenses left 3 User3 joins Licenses left 2 User4 joins Licenses left 1 User5 joins Licenses left 0 User6 joins All licenses are in use User1 exists Licenses left 1
Download the source code
This was an example about Java Semaphore.