is an advanced lock that allows at most N threads to proceed after
which it begins blocking. N is specified in the constructor.
in the semaphore object blocks if a permit is not available, else it
takes a permit and proceeds. Each call to release()
adds a permit, potentially making room for a waiting thread to
proceed. However, no actual permit objects are used; the Semaphore
just keeps a count of the number available and acts accordingly.
Semaphores are often used to restrict the number of threads than can
access some (physical or logical) resource.
constructor for this class optionally accepts a fairness
parameter which if set to true, guarantees that threads calling
acquire() obtain the lock in a FIFO fashion thus guaranteeing