132

Is there a Mutex object in java or a way to create one? I am asking because a Semaphore object initialized with 1 permit does not help me. Think of this case:

try {
   semaphore.acquire();
   //do stuff
   semaphore.release();
} catch (Exception e) {
   semaphore.release();
}

if an exception happens at the first acquire, the release in the catch block will increase the permits, and the semaphore is no longer a binary semaphore.

Will the correct way be?

try {
   semaphore.acquire();
   //do stuff
} catch (Exception e) {
   //exception stuff
} finally {
   semaphore.release();
}

Will the above code ensure that the semaphore will be binary?

Prince
  • 20,353
  • 6
  • 39
  • 59
Noam Nevo
  • 3,021
  • 10
  • 35
  • 49
  • Did you find out this behaviour empirically? Is the implementation such that executing release() on a 1-permit Semaphore adds an extra permit even if it's holding currently another, really ? – Whimusical Dec 01 '15 at 19:12
  • Look at the javadoc for java.util.concurrent.locks.AbstractQueuedSynchronizer. It has an example of how to write a Mutex class. -dbednar – joe Jun 29 '13 at 00:12

8 Answers8

147

Any object in Java can be used as a lock using a synchronized block. This will also automatically take care of releasing the lock when an exception occurs.

Object someObject = ...;

synchronized (someObject) {
  ...
}

You can read more about this here: Intrinsic Locks and Synchronization

casablanca
  • 69,683
  • 7
  • 133
  • 150
  • Very helpful buy i wanted to use a semaphore. – Noam Nevo Mar 13 '11 at 17:41
  • 12
    @Noam: just compare the code with semaphore and with `synchronized`, you'll see what is better readable and less error-prone. – Vlad Mar 13 '11 at 19:11
  • 25
    The synchronized keyword cannot be used if you expect to release the lock in a different method (e.g. `transaction.begin(); transaction.commit()`). – Hosam Aly May 29 '14 at 22:13
  • and its not object oriented..its much of low level synchronisation – anshulkatta Dec 10 '15 at 10:52
  • 1
    Also look into `someObject.wait(timeout)` and `someObject.notify()` while you're looking at the code of this answer. – Daniel F May 21 '19 at 15:23
127

See this page: http://www.oracle.com/technetwork/articles/javase/index-140767.html

It has a slightly different pattern which is (I think) what you are looking for:

try {
  mutex.acquire();
  try {
    // do something
  } finally {
    mutex.release();
  }
} catch(InterruptedException ie) {
  // ...
}

In this usage, you're only calling release() after a successful acquire()

payne
  • 13,833
  • 5
  • 42
  • 49
40

No one has clearly mentioned this, but this kind of pattern is usually not suited for semaphores. The reason is that any thread can release a semaphore, but you usually only want the owner thread that originally locked to be able to unlock. For this use case, in Java, we usually use ReentrantLocks, which can be created like this:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

private final Lock lock = new ReentrantLock(true);

And the usual design pattern of usage is:

  lock.lock();
  try {
      // do something
  } catch (Exception e) {
      // handle the exception
  } finally {
      lock.unlock();
  }

Here is an example in the java source code where you can see this pattern in action.

Reentrant locks have the added benefit of supporting fairness.

Use semaphores only if you need non-ownership-release semantics.

rouble
  • 16,364
  • 16
  • 107
  • 102
  • 9
    Actually this should be the (only) correct answer for this question. Clear explanation of differences between semaphore and mutual exclusion lock. Using a semaphore with `count=1` is not a mutual exclusion lock. – Kaihua Sep 09 '18 at 23:50
  • 4
    Glad someone pointed out. For exclusive access to a resource mutexes are the way to go. Binary semaphores are not mutex, semaphores should be used more as signalling mechanism. – Shivam Tripathi Aug 28 '19 at 05:02
  • 1
    Rouble: So is `lock` e.g. `ReentrantLock` a `mutex`? I am not sure why `mutex` and `binary semaphore` are being taken equated to be same entity. `Semaphore` can be released by any thread, so that may not guarantee guarding `critical section`. Any thoughts? – CuriousMind May 30 '20 at 20:35
  • 1
    @Kaihua: I resonate with your thought. This answer brings the key difference – CuriousMind May 30 '20 at 20:36
31
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


private final Lock _mutex = new ReentrantLock(true);

_mutex.lock();

// your protected code here

_mutex.unlock();
Thousand
  • 6,562
  • 3
  • 38
  • 46
Argv
  • 329
  • 3
  • 2
  • 5
    In what way is this superior to the solutions already provided? How does it solve the problem the original asker was having? – Martin Sep 23 '12 at 01:19
  • @Martin: `"Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements."`, from: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html ...although you have a point. Argv's answer doesn't illustrate or explain these operations. – FrustratedWithFormsDesigner May 11 '15 at 19:45
  • 4
    This is a recursive mutex that will allow multiple re-locks from the same thread, which can be problematic. A "true", basic mutex (non-recursive, C++-style) would allow only one lock at a time. If you change your line to `private final ReentrantLock _mutex = ...`, you can use [getHoldCount()](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html#getHoldCount()) to return the number of thread re-locks. (You could apply a `Condition` to prevent this. [See the API](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html).) – EntangledLoops Nov 10 '15 at 23:45
  • So mutex is just a lock – LookIntoEast Aug 18 '21 at 05:33
6

I think you should try with :

While Semaphore initialization :

Semaphore semaphore = new Semaphore(1, true);

And in your Runnable Implementation

try 
{
   semaphore.acquire(1);
   // do stuff

} 
catch (Exception e) 
{
// Logging
}
finally
{
   semaphore.release(1);
}
Sashi Kant
  • 13,277
  • 9
  • 44
  • 71
  • This is how I have done it, but I am not quite sure if this is the way to go. – noBillSide Aug 19 '16 at 07:16
  • 1
    According to https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html#release() "There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire. Correct usage of a semaphore is established by programming convention in the application." If the acquire throws an exception, the release in the finally will incorrectly release a permit. Other examples in this thread show the correct flow. – Brent K. Aug 29 '19 at 15:30
4

Mistake in original post is acquire() call set inside the try loop. Here is a correct approach to use "binary" semaphore (Mutex):

semaphore.acquire();
try {
   //do stuff
} catch (Exception e) {
   //exception stuff
} finally {
   semaphore.release();
}
smile-on
  • 2,073
  • 1
  • 20
  • 20
1

Each object's lock is little different from Mutex/Semaphore design. For example there is no way to correctly implement traversing linked nodes with releasing previous node's lock and capturing next one. But with mutex it is easy to implement:

Node p = getHead();
if (p == null || x == null) return false;
p.lock.acquire();  // Prime loop by acquiring first lock.
// If above acquire fails due to interrupt, the method will
//   throw InterruptedException now, so there is no need for
//   further cleanup.
for (;;) {
Node nextp = null;
boolean found;
try { 
 found = x.equals(p.item); 
 if (!found) { 
   nextp = p.next; 
   if (nextp != null) { 
     try {      // Acquire next lock 
                //   while still holding current 
       nextp.lock.acquire(); 
     } 
     catch (InterruptedException ie) { 
      throw ie;    // Note that finally clause will 
                   //   execute before the throw 
     } 
   } 
 } 
}finally {     // release old lock regardless of outcome 
   p.lock.release();
} 

Currently, there is no such class in java.util.concurrent, but you can find Mutext implementation here Mutex.java. As for standard libraries, Semaphore provides all this functionality and much more.

Zz'Rot
  • 824
  • 1
  • 7
  • 24
pogrebniuk
  • 11
  • 2
0

To ensure that a Semaphore is binary you just need to make sure you pass in the number of permits as 1 when creating the semaphore. The Javadocs have a bit more explanation.

Sanjay T. Sharma
  • 22,857
  • 4
  • 59
  • 71
  • No sorry. It *CAN* be used as binary semaphore, it's not a binary semaphore. If you call many release() on it you allow many acquiring threads to be released – Jack Jun 28 '21 at 21:38