
Semaphores are an often misunderstood and under used tool for restricting access to resources. They are ignored for other ways of controlling access to resources. But semaphores give us a tool set that goes beyond what normal synchronization and other tools can give us.
The simplest way to describe a semaphore is a mechanism to allows n units to be acquired to access particular resource. A semaphore is a synchronization object that controls access by multiple processes to a common resource in a parallel programming environment. Semaphores are widely used to control access to files and shared memory.
Semaphore is a technique used to control access to common resource (like database connection, file operation, ports etc) for competing multiple processes. Semaphore maintains a counter which keeps track of the number of resources available. When a process requests access to resource, semaphore checks the variable count and if it is less than total count then grants access and subsequently reduces the available count.
Semaphore is just a gatekeeper guarding the resources. If available grants access and otherwise asks the processes to wait.
- When the resource count is more than 1, then this is called counting semaphore.
- If resource count is only one and the state value is restricted to on/off, then it is called binary semaphore.
Very useful Book to learn about concurrency...

This concurrency utility can be very useful to implement producer consumer design pattern or implement bounded pool or resources like
Thread Pool,
DB Connection pool etc. java.util.Semaphore class represent a Counting semaphore which is initialized with number of permits. Semaphore provides two main method acquire() and release() for getting permits and releasing permits.
Counting Semaphore Example:
Suppose we got requirement to have resouce which can be accessed by 3 resource at a time while other request has to wait for resource to be free for access. Below is the code to implement such behaviour.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | MyThread Class:
package semaphorepool;
class MyThread extends Thread {
MyLimitedResource resource;
public MyThread(String s, MyLimitedResource r) {
super(s);
resource=r;
}
public void run() {
resource.printResourceName();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | MyLimitedResource class
package semaphorepool;
import java.util.Calendar;
public class MyLimitedResource {
ConnectionLimiter con;
public MyLimitedResource(ConnectionLimiter connectionLimiter){
con=connectionLimiter;
}
public void printResourceName(){
try{
String resourceHeldBy= Thread.currentThread().getName();
con.acquire();
Calendar cal = Calendar.getInstance();
cal.getTime();
System.out.println(cal.getTime()+ "- Currently Resource Held by "+ resourceHeldBy);
Thread.sleep(10000);
con.release();
System.out.println(cal.getTime()+ "- Resource Released by "+ resourceHeldBy);
}catch (InterruptedException i){
i.printStackTrace();
}
}
}
|
ConnectionLimiter Class
package semaphorepool;
import java.util.concurrent.Semaphore;
public class ConnectionLimiter {
private final Semaphore semaphore;
public ConnectionLimiter(int maxConcurrentRequests) {
semaphore = new Semaphore(maxConcurrentRequests);
}
public void acquire() throws InterruptedException {
semaphore.acquire();
}
public void release() {
try {
System.out.println("Clean up before releasing resource");
} finally {
semaphore.release();
}
}
}
Semaphore Test class:
package semaphorepool;
public class SemaphoreTest {
public static void main(String[] args) {
ConnectionLimiter limiter = new ConnectionLimiter(3);
final MyLimitedResource resource = new MyLimitedResource(limiter);
for (int i = 0; i < 10; i++) {
new MyThread("Thread-" + i, resource).start();
}
}
}
Output (PS: This may vary as per JVM version and OS settings)
Sun Sep 14 13:17:37 CEST 2014- Currently Resource Held by Thread-2
Sun Sep 14 13:17:37 CEST 2014- Currently Resource Held by Thread-0
Sun Sep 14 13:17:37 CEST 2014- Currently Resource Held by Thread-1
Clean up before releasing resource
Sun Sep 14 13:17:37 CEST 2014- Resource Released by Thread-2
Sun Sep 14 13:17:47 CEST 2014- Currently Resource Held by Thread-4
Clean up before releasing resource
Sun Sep 14 13:17:37 CEST 2014- Resource Released by Thread-0
Clean up before releasing resource
Sun Sep 14 13:17:37 CEST 2014- Resource Released by Thread-1
Sun Sep 14 13:17:47 CEST 2014- Currently Resource Held by Thread-6
Sun Sep 14 13:17:47 CEST 2014- Currently Resource Held by Thread-5
Clean up before releasing resource
Sun Sep 14 13:17:57 CEST 2014- Currently Resource Held by Thread-8
Sun Sep 14 13:17:47 CEST 2014- Resource Released by Thread-4
Clean up before releasing resource
Clean up before releasing resource
Sun Sep 14 13:17:57 CEST 2014- Currently Resource Held by Thread-3
Sun Sep 14 13:17:47 CEST 2014- Resource Released by Thread-5
Sun Sep 14 13:17:47 CEST 2014- Resource Released by Thread-6
Sun Sep 14 13:17:57 CEST 2014- Currently Resource Held by Thread-9
Clean up before releasing resource
Sun Sep 14 13:17:57 CEST 2014- Resource Released by Thread-8
Sun Sep 14 13:18:07 CEST 2014- Currently Resource Held by Thread-7
Clean up before releasing resource
Sun Sep 14 13:17:57 CEST 2014- Resource Released by Thread-3
Clean up before releasing resource
Sun Sep 14 13:17:57 CEST 2014- Resource Released by Thread-9
Clean up before releasing resource
Sun Sep 14 13:18:07 CEST 2014- Resource Released by Thread-7</pre>
Dangers/Pitfalls
As with most methods of locking or synchronization, there are some potential issues.
The number one thing to remember is, always release what you acquire. Always write release code in finally so irrespective of exception acquired resource will be released. (We have used try..finally in our code above)
Reference:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html