sync provides basic synchronization primitives: mutexes, wait groups, one-time initialization, condition variables, and two specialized concurrent-safe containers.
A sync.Mutex protects the shared counter and a sync.WaitGroup tracks the 100 goroutines writing to it.
var (
mu sync.Mutex
wg sync.WaitGroup
counter int
)
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println(counter)Every increment is serialized by the lock, so the final count is exact regardless of goroutine scheduling.
Terminal
$ go run main.go
100Mutex
| Function | Description |
|---|---|
Lock() mu.Lock() | Blocks until the lock is free, then acquires it |
Unlock() mu.Unlock() | Releases the lock; panics if the mutex isn't currently locked |
TryLock() bool ok := mu.TryLock() | Acquires the lock without blocking, reporting whether it succeeded |
RWMutex
| Function | Description |
|---|---|
Lock() / Unlock() mu.Lock() | Exclusive write lock; blocks every other reader and writer |
RLock() / RUnlock() mu.RLock() | Shared read lock; any number of readers can hold it at once |
TryLock() bool ok := mu.TryLock() | Acquires the write lock without blocking |
TryRLock() bool ok := mu.TryRLock() | Acquires a read lock without blocking |
WaitGroup
| Function | Description |
|---|---|
Add(delta int) wg.Add(1) | Adds delta to the counter; delta may be negative |
Done() defer wg.Done() | Decrements the counter by one, shorthand for Add(-1) |
Wait() wg.Wait() | Blocks until the counter returns to zero |
Once
| Function | Description |
|---|---|
Do(f func()) once.Do(setup) | Runs f exactly once, no matter how many goroutines call Do concurrently |
Cond
| Function | Description |
|---|---|
NewCond(l Locker) *Cond c := sync.NewCond(&mu) | Creates a Cond backed by an existing Locker, usually a *Mutex |
Wait() c.Wait() | Unlocks the Locker, suspends the goroutine, and relocks before returning |
Signal() c.Signal() | Wakes one goroutine waiting on the condition, if any are waiting |
Broadcast() c.Broadcast() | Wakes every goroutine waiting on the condition |
Map
| Function | Description |
|---|---|
Load(key any) (value any, ok bool) v, ok := m.Load("id") | Reads the value stored for key |
Store(key, value any) m.Store("id", 1) | Sets the value for key |
Delete(key any) m.Delete("id") | Removes the value stored for key |
LoadOrStore(key, value any) (actual any, loaded bool) v, loaded := m.LoadOrStore("id", 1) | Returns the existing value if present, otherwise stores and returns value |
LoadAndDelete(key any) (value any, loaded bool) v, ok := m.LoadAndDelete("id") | Removes key and returns the value that was stored |
Swap(key, value any) (previous any, loaded bool) old, loaded := m.Swap("id", 2) | Stores value and returns the value it replaced |
CompareAndSwap(key, old, new any) bool m.CompareAndSwap("id", 1, 2) | Swaps only if the stored value equals old |
CompareAndDelete(key, old any) bool m.CompareAndDelete("id", 2) | Deletes only if the stored value equals old |
Range(f func(key, value any) bool) m.Range(func(k, v any) bool { return true }) | Calls f for each entry until f returns false; iteration order isn't guaranteed |
Pool
| Function | Description |
|---|---|
New func() any p := sync.Pool{New: func() any { return new(bytes.Buffer) }} | Factory field called to create a value whenever Get finds the pool empty |
Get() any buf := p.Get().(*bytes.Buffer) | Removes and returns an item from the pool, or calls New if the pool is empty |
Put(x any) p.Put(buf) | Adds x back to the pool for a later Get to reuse |