How and why can a Semaphore give out more permits than it was initialized with?
I am reading the book Java Concurrency in Practice. In a section about java.util.concurrent.Semaphore
, the below lines are present in the book. It is a comment about its implementation of "virtual permit" objects
The implementation has no actual permit objects, and
Semaphore
does not associate dispensed permits with threads, so a permit acquired in one thread can be released from another thread. You can think ofacquire
as consuming a permit andrelease
as creating one; aSemaphore
is not limited to the number of permits it was created with.
Can somebody explain this? I am having trouble understanding this. If we create a pool of fixed size, we create a fixed开发者_如何学Go number of "permits". From the above statement, it looks like the "permits" can keep growing. Why is it designed this way?
Instead of "handing out" permit objects, the implementation just has a counter. When a new permit is "created" the counter is increased, when a permit is "returned" the counter is decreased.
This makes for much better performance than creating actual objects all the time.
The tradeoff is that the Semaphore itself cannot detect certain kinds of programming errors (such as unauthorized permit cash-ins, or semaphore leaks). As the coder, you have to make sure to follow the rules on your own.
I think that it means the times what we may require Semaphore as the times we released "extra" and plus the permits it created with.
Such as:
Semaphore s = new Semaphore(1); // one permit when initialize
s.acquire();
s.release();
s.release(); // "extra" release.
At this moment, this semaphore allows one permit originally and one "extra" permit
Can somebody explain this ? From the above statement, it looks like the "permits" can keep growing.
A semaphore is a counter of permits. acquire is like decrement which waits rather than go below zero. It has no upper limit.
Why is it designed this way ?
Because its simple to do so.
As mentioned in first post "Semaphore is not limited to the number of permits it was created with"
Every call to .release() API will increase the permit count by one. So Semaphores doesn't have a fixed permit size
Perhaps the last line " a Semaphore is not limited to the number of permits it was created with" is your source of confusion.
A semaphore when created is initialized with a fixed set of permits. This then becomes the maximum number of permits that the semaphore can simultaneuosly dispense at any time during the life time of that semaphore. You cannot dynamically increase this number except by re-initializing the semaphore .
The meaning if the quoted line ( from JCIP ) is this : First , the semantics of how a semaphore works is not limited to the details of issuing and regaining a permit - this is manifested in the fact that any thread can that has access the semaphore can have a permit released ( even though this thread did not own the permit at the first place)
Second , you can dynamically reduce the maximum permits of a semaphore - by calling reducePermits(int)
method.
It is surprising to some of us.
You can easily subclass up a bounded semaphore.
/**
* Terrible performance bounded semaphore.
**/
public class BoundedSemaphore extends Semaphore {
private static final long serialVersionUID = -570124236163243243L;
final int bound;
public BoundedSemaphore(int permits) {
super(permits);
bound=permits;
}
@Override
synchronized public void acquire() throws InterruptedException {
super.acquire();
}
@Override
synchronized public boolean tryAcquire() {
return super.tryAcquire();
}
@Override
synchronized public void release() {
if( availablePermits()<bound){
super.release();
}
}
@Override
synchronized public void acquire(int count) throws InterruptedException {
super.acquire(count);
}
@Override
synchronized public boolean tryAcquire(int count) {
return super.tryAcquire(count);
}
@Override
synchronized public void release(int count) {
if( availablePermits()<bound){
super.release(bound-availablePermits());
}
}
}
精彩评论