Mutex vs semaphore
A mutex (mutual exclusion lock) lets exactly one thread into a section of code at a time. A semaphore holds a number of permits, and lets that many threads in at once. Use a mutex to protect shared data; use a semaphore to limit how many threads do something at the same time, like calls to an API.
Mutex: one at a time
Two goroutines increment a counter. The mutex lets one in; the other waits until it unlocks, then sees the fresh value.
With a mutex, one goroutine at a time runs count++. The other waits for the lock.
Semaphore: N at a time
Four threads want an API that allows two calls at once. A semaphore with 2 permits lets two in, and each release lets exactly one more in.
Four threads want to call an API that allows two at a time. A Semaphore with 2 permits keeps the rest waiting.
A semaphore with one permit
With one permit, only one thread is ever inside, just like a lock. The difference is ownership: a permit has no owner, so any thread may release it.
With one permit, the four workers call the API one at a time. The semaphore works like a lock.
Who may unlock?
Java’s ReentrantLock has an owner: only the thread that locked it may unlock it. A semaphore permit has none. And Go’s sync.Mutex has no owner either: another goroutine may unlock it.
Common questions
What's the difference between a mutex and a semaphore?
A mutex lets one thread at a time into a critical section. A semaphore holds N permits and lets N threads in at once; acquire() takes a permit or waits, release() gives one back.
Is a semaphore with one permit the same as a mutex?
It also lets one thread in at a time, but a permit has no owner: any thread can release it. Java's ReentrantLock does have an owner, and unlock() from another thread throws IllegalMonitorStateException.
Does a Go mutex have an owner?
No. A locked sync.Mutex isn't tied to a goroutine, and another goroutine may unlock it. Keeping Lock and Unlock in the same function is a convention, not a rule the runtime checks.
Every timeline here is checked against a real program in CI. How we verify