A semaphore acts as a limiter of available resource pool depth; for example, a semaphore with a capacity of 10 allows a maximum of 10 threads to acquire it at once, and any further threads that attempt to acquire it will block until one of the other threads releases it.
This is somewhat different from ordinary mutual exclusion or monitor locking, which is typically used to prevent more than one thread from simultaneously modifying the same variables and causing inconsistent results or program state.
Consider, for example, a connection pool with a limit of 10 connections in it. Each thread that needs a connection will acquire the semaphore for the duration of its use of a connection (which prevents too many threads asking for connections at once), but the pool object must also use synchronized blocks or methods when taking connections out of its internal collection or putting them back in, to prevent such things as losing track of connections or mistakenly handing the same connection to two different threads because they asked simultaneously.