sync/atomic

Guided tour · Concurrency · pkg.go.dev →

Low-level atomic operations. Lock-free counters, flags, and pointers — faster than a Mutex when the state fits in a word.

Typed wrappers (Go 1.19+) — prefer these

atomic.Int32, Int64, Uint32, Uint64, Uintptr, Bool, Pointer[T], Value. Methods like Load, Store, Add, CompareAndSwap, Swap.

atomic.Int64 counter

var hits atomic.Int64

for i := 0; i < 5; i++ {
    go hits.Add(1)
}
time.Sleep(time.Millisecond)
fmt.Println(hits.Load())

atomic.Bool flag

var closed atomic.Bool

if closed.CompareAndSwap(false, true) {
    // we're the one who closed it
    close(ch)
}

atomic.Pointer[T] — lock-free pointer swap

Perfect for hot-reloadable config or snapshot-style data structures.

var cfgP atomic.Pointer[Config]
cfgP.Store(&Config{...})

// readers
cfg := cfgP.Load()

// hot-reload
cfgP.Store(newCfg)

atomic.Value — for arbitrary types (pre-generics)

Still useful if you need something other than a pointer. The value must always be the same concrete type.

var v atomic.Value
v.Store("hello")
s := v.Load().(string)

Raw functions — still here for interop

The original AddInt32, LoadUint64, etc. still work. Prefer the typed wrappers in new code — same performance, harder to misuse.