Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java semaphore increases the number of permits when I do release more than number of the acquires

I'm learning about Mutex and Semaphore in Java. So I thought of getting my hands dirty.

I understand that mutex is semaphore with single permit from this link and mutex has the concept of ownership from this link.

To demonstrate ownership I wrote below program and found below output. When I do release more than acquires, it actually increases the number of permits.

Below is the program.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;

public class MutexOwnerShipDemo {
    public static void main(String[] args) {
        Semaphore mutex = new Semaphore(1);
        final ExecutorService es = Executors.newSingleThreadExecutor();
        try {
            // acquire mutex lock permit in main thread
            mutex.acquire();

            // release the lock in different thread
            Future mutexWait = es.submit(() -> mutex.release());
            mutexWait.get();
            System.out.println("mutexWait.isDone() " + mutexWait.isDone() );
            System.out.println("successfully released permits for mutex \n " +
                "available permits are " + mutex.availablePermits());

            // release the lock in main thread
            mutex.release();
            System.out.println( "available permits are " + mutex.availablePermits());

            // release lock in main thread once again
            mutex.release();
            System.out.println( "available permits are " + mutex.availablePermits());
        } catch (Exception e) {

        }
        Runtime.getRuntime().addShutdownHook(new Thread(() -> es.shutdownNow()));
        System.out.println(es.isShutdown());
    }
}

The output is -

mutexWait.isDone() true
successfully released permits for mutex 
available permits are 1
available permits are 2
available permits are 3
false

Is this behavior expected. If so, how this works

My java installation details -

$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
like image 715
Rajkumar Natarajan Avatar asked Sep 09 '18 19:09

Rajkumar Natarajan


People also ask

Can thread release permits on a semaphore without having them?

There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire().

What does semaphore release do?

Exits the semaphore a specified number of times and returns the previous count.

What is permit in semaphore?

the constructor parameter permits (initial semaphore counter) is the number of calls to Semaphore. aquire() that can be made before the counter (permits) is zero, and the acquire() blocks. 1 is a normal value, to ensure that only one thread passes the acquire.

Can release be called on a semaphore before acquire?

Yes, a negative value means you have processes waiting for the semaphore to be released. A positive value means you can call acquire that many times before the semaphore blocks.


2 Answers

A couple of things:

  • you're using a Semaphore, which can have any number of permits, so yes it is expected. See the Javadoc:

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.

  • you're not using multiple threads since you're always blocking in futures. Your code is fully sequential.
  • when people say a mutex is a semaphore with a single permit, they're talking about the abstract concepts, not the Java implementations. Example of mutexes in Java would be a ReentrantLock, or a simple Object used with a synchronized block.
like image 37
Dici Avatar answered Oct 17 '22 11:10

Dici


Yes, it's the expected behaviour cited in the documentation:

[...] Releases a permit, increasing the number of available permits by one. [...] There is no requirement that a thread that releases a permit must have acquired that permit by calling acquire().

You can release as many permits as you want to:

Semaphore semaphore = new Semaphore(0);
semaphore.release(10); // it's fine
System.out.println(semaphore.availablePermits()); // 10

You can't obtain a random number of permits (precisely, a number that exceeds the current number of permits available), though:

Semaphore semaphore = new Semaphore(0);
semaphore.acquire(10); // you are blocked here

Semaphore semaphore = new Semaphore(0);
System.out.println(semaphore.tryAcquire(10)); // false
like image 82
Andrew Tobilko Avatar answered Oct 17 '22 10:10

Andrew Tobilko