How to release all permissions for a Java semaphore

So this code:

int usedPermits = totalPermits - semaphore.availablePermits();
semaphore.release(usedPermits);

      

It is not thread safe, because if another thread releases the permission between the two lines, the semaphore's capacity will actually exceed its original maximum.

This works in my situation, as this strip of code is 1) single threaded and 2) the only place from which permissions are issued, which might just illustrate the fact that "free all" and "acquire / free" are two incompatible design patterns on the same and the same object.

However, I want to ask if there is a preferred pattern with less fine-grained thread synchronization policy.

+3


source to share


4 answers


As explained in other answers, there is a solution to make your piece of code atomic. However, there is no guarantee that it will solve the problem in general setup simply because this code may not be correct in all situations.

Either the permissions are released by actions that use them, in which case this code is superfluous: the semaphore will naturally replenish, otherwise they won't, in which case you need this piece of code, and it will be safe as long as you don't nothing strange about it.

Note that you are stating that you want to limit the rate of actions per slice of time (here a minute), but you must take into account that actions can take longer than a minute. There are two different things that you can limit here:

  • the number of actions starting with a quantum,
  • the number of operations performed in a quantum

If you want to restrict the former, then you need your permissions replenishment code and let the activists keep their permissions. If you want to handle the second case, then you have to force actions to acquire and release their permission on startup and shutdown, respectively.



If you are afraid of abusing the semaphore in some actions, just forbid its use in the operation code itself. Indeed, rate limiting is completely orthogonal to the semantics of the activity, and it is better to separate this functionality from the main activity code. Therefore, you must postpone any scheduled operation with the semaphore-handling code:

class RateLimitedRunnable implements Runnable {
    Runnable runnable;
    RateLimitedRunnable(Runnable r) { runnable = r; }
    void Run() {
        semaphore.acquire();
        runnable.run();
        semaphore.release(); // remove if only limiting starts
    }
}

      

The example (untested) code above describes the possible handling of semaphore usage from real activity, thereby eliminating any potential abuse. If an internal activity requires access to a semaphore, it should only be to retrieve its current state, and a special interface can be defined to provide limited access.

Note. I use the term "activity" here as a mean for threads or processes because the discussion of using semaphores is more general than the Java context.

+3


source


It is not thread-safe because if another thread releases a permit between the two lines, the semaphore's capacity will actually grow beyond its original maximum.

This needs to be solved with help synchronization

, also ensure that everyone is semaphore.release()

in the block synchronized

, for example.

synchronize(lock) {
    int usedPermits = totalPermits - semaphore.availablePermits();
    semaphore.release(usedPermits);
}

      



However, this may not be enough if you want to ensure that the number of permissions does not exceed totalPermits

, because even with a synchronized

release all block , if the stream named release

after the word semaphore

will exceed totalPermits

.

You can implement a function that is threads

called to resolve the release without a direct call semaphore.release()

, eg.

void limitedRelease(){
  synchronize(lock) {
    if(semaphore.availablePermits() < totalPermits ) {
      semaphore.release();
    }    
  }  
}

      

0


source


Overlaying something on the Semaphore is a bit weird if even possible. This will also cause an explosion - if you limit 10,000 QPS, every second you go to reset and get 10,000 requests at the same time. Why not use the existing RateLimiter implementation ?:

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/util/concurrent/RateLimiter.html

Or take a look at the code for inspiration, at least:

http://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/util/concurrent/RateLimiter.java?name=v13.0-rc2

0


source


Why don't you extend the standard Semaphore class and override its methods, but make them synchronized:

public class Semaphore extends java.util.concurrent.Semaphore {
public Semaphore(int permits)
{
    super(permits);
}

public synchronized void releaseAll()
{
    super.release(super.drainPermits());
}   
}

      

0


source







All Articles