Compare

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.

GoFix it with sync.Mutex

With a mutex, one goroutine at a time runs count++. The other waits for the lock.

012345678910go g1go g2wg.Wait()main: print countg1: mu.Lock()Lockcount++ → 1g1: mu.Unlock()waits in mu.Lock()count++ → 2g2: mu.Unlock()
Play it step by step

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.

JavaLimit concurrency with a Semaphore

Four threads want to call an API that allows two at a time. A Semaphore with 2 permits keeps the rest waiting.

01234567callApi(1)callApi(2)acquire()callApi(3)acquire()callApi(4)
Play it step by step

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.

JavaA Semaphore with 1 permit

With one permit, the four workers call the API one at a time. The semaphore works like a lock.

0123456789101112callApi(1)acquire()callApi(2)acquire()callApi(3)acquire()callApi(4)
Play it step by step

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