AsyncSemaphore
An interface representing a non-blocking semaphore.
A semaphore maintains a set of permits and each acquire()
blocks if necessary until a permit is available, and then takes it. Each release()
adds a permit, potentially releasing an acquirer.