I’m a swiss Master student in Computer Science. I’m very interested in C++, open source projects, Linux, Intel Assembly and Agile. I'm currently working on Eddi, a new programming language that I created to improve my skills in C++. I've also worked a lot on Java technologies (Sprint, Osgi, Play!, ...), but I'm not currently working with Java anymore. Baptiste is a DZone MVB and is not an employee of DZone and has posted 51 posts at DZone. You can read more from them at their website. View Full User Profile

Java Concurrency – Part 4 : Semaphores

09.08.2010
| 16496 views |
  • submit to reddit

We continue with the Java Concurrency theme with semaphores. Semaphores are also a way to synchronize threads.

Semaphores are a really simple concept, invented by the famous Dutch computer scientist Edsger Dijkstra. Basically a semaphore is a counter (integer) that allows a thread to get into a critical region if the value of the counter is greater than 0. If it’s the case, the counter is decremented by one. Otherwise, the thread waits until it can go. And when the thread leaves the critical region, the counter is incremented by one to allow one more thread to pass through the critical region. A semaphore is created with a certain value for its counter. So, you can execute two actions on a semaphore P and V.

For example, if you have a critical section that cannot be executed concurrently, you can use a semaphore :

sem mutex = new sem(1)

P(mutex)
//Critical region
V(mutex)

So you must always call the P operation by yourself before the critical region and V after it. We call a mutex (mutual exclusion) a semaphore with a value of one. So only one thread can enter the region guarded by the semaphore. This is the most used semaphore. The other use of semaphore is to guard a set of resources like database connections or a data pool.

In Java, a semaphore is created using the java.util.concurrent.Semaphore class. You can create it easily :

Semaphore mutex = new Semaphore(1);
Semaphore available = new Semaphore(100);

The P and V operations are represented using the acquire and release methods. The method acquire can be interrupted if the thread is interrupted. There is an ininterruptible version with the method acquireUninterruptibly(). There is also a third version with the tryAcquire method. This method acquires a permit only if there is one permit available, otherwise, this method return false. All the waiting methods also have an overloaded version with a timeout. You can also acquire several permits at once using the permits argument to the different versions of acquire methods.

A little example with a mutex using the same example as the previous post on Java concurrency :

public class Example {
private int value = 0;

private final Semaphore mutex = new Semaphore(1)

public int getNextValue() throws InterruptedException {
try {
mutex.acquire();
return value++;
} finally {
mutex.release();
}
}
}

For more information about Semaphore in Java, the best is to consult the Javadoc of the Semaphore class.

To conclude, semaphores are a powerful way to solve concurrency problems, but this is not adapted to all problems. If you only need mutual exclusion, synchronized blocks are a better solution. The problems with semaphores is that you can forget to call the release method and this can cause deadlocks that are sometimes difficult to find.

From http://www.baptiste-wicht.com/2010/08/java-concurrency-part-4-semaphores/

Published at DZone with permission of Baptiste Wicht, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Lukasz Zwierko replied on Thu, 2010/09/09 - 3:11am

Hi,

nice article, just one thing: you should really not use word 'mutex' as a semaphore name as it might confuse some people. Mutexes are different (though similar) entities than semaphores. 

Basic differences (though this might be implementation dependent)  are:

1. Mutex can be taken only once (so it's like semaphore(1)), but.. see p.3

2. Mutex can be only release from the same thread it was taken

3.  Thread that took mutex can take it again recursively (implementation dependent), provided that  it releases it as many times as it was taken. This can be useful although sometimes considered bad coding style.

4. And the most difference, although valid only for real time operating systems (RTOS)- priority inversion. Take situation where that low priority thread A gets mutex ownership, and later high priority thread B tries to tke the mutex. Thread B has to wait for mutex to be released, so it would actually becomes low priority thread as it has to wait for thread A to release the mutex. Thread A, being low priority, can be unfortunately preempted by all other tasks, causing thread B - high priority to be preempted as a consequence.

To prevent such situation the mutexes can behave bit differently - they an inherit priority of the highest prioryti thread waiting on them. So in the example blow, thread A would be given priority of thread B, for the time that it'd be the mutes owner. After releasing mutex, it's normal priority would be restored.

ow important this is? see Mars pathfinder story:

http://research.microsoft.com/en-us/um/people/mbj/mars_pathfinder/mars_pathfinder.html

 This is of course not important for java, still doesn't hurt to know. 

cheers

 

Tim Boudreau replied on Thu, 2010/09/09 - 4:06am

The problem that you note at the end is indeed a real one. Any kind of call that can just take lock something without guaranteeing how and when it will be unlocked it is dangerous enough that the convenience is not worth it. In my career I've seen exactly one case where it was useful to take a lock on one thread and release it on another.

With minimal additional code you can ensure that such a situation is nearly impossible - just make the locking construct private and used in only one method, so the try-finally block is guaranteed; guard any resource that should only be accessed while holding the lock by passing that resource into a Runnable-like object's single method. I.e.

public interface ThingUser {
   public void withThing (Thing thing);
}
public class ThingService {
   private final Thing thing;
   private final Semaphore mutex = new Semaphore(5);
   public void useThing (ThingUser user) {
       try {
          mutex.acquire(1);
          user.withThing (user);
       } finally {
          mutex.release();
       }
   }
}
Obviously, sometimes you're stuck with existing code that needs some locking, and this sort of thing is not possible. But where you can use this pattern, it's both less bug-prone and has benefits for anyone calling the code - it's much easier to remember "to use a Thing, you have to write a ThingUser" than it is to remember "if you call a Thing, you should be holding this lock". This way, you build a real, but fairly transparent locking model, and all of the points where the lock is used are known and easily findable by a class usage search, so you never have to do a pass of looking at every usage of mutex.acquire() or synchronized() in your codebase when you want to change the locking model.

Lukasz Zwierko replied on Thu, 2010/09/09 - 8:58am in response to: Tim Boudreau

Hi Tim,

 

I totally agreee with you. The general pattern I try to follow is that all the logic is in private methods and the only place the mutexes are acquired are interface methods.

Anyway as for the c# Smaphore classes, I actually think that all the mutex-like locking should be done with synchronized keyword. This saves you from having to use try-finally construct.

Anyway what can you use the semaphore for in java ? only obvious use is the wait-signal pattern one thread waiting for others to be signaled.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.