Go中引用类型(如slice、map、channel等)不保证并发安全,多goroutine读写需显式同步;推荐按场景选用sync.RWMutex、sync.Map、sync/atomic或channel。
Go 中的切片(slice)、map、channel、指针、函数、接口等属于引用类型,但它们的“引用”特性只表示底层数据结构共享同一块内存,并不意味着操作是原子的或线程安全的。比如多个 goroutine 同时对一个 map 进行读写,会直接触发 panic(fatal error: concurrent map writes);对切片追加元素(append)也可能因底层数组扩容导致数据竞争。
以下情况需要显式同步控制:
sync.RWMutex 或 sync.Map
*int 被多个 goroutine 增减)—— 基础类型操作虽小,但非原子,
需 sync/atomic 或互斥锁优先按场景选合适工具,不盲目上 sync.Mutex:
sync.RWMutex 包裹原生 map,读用 RLock,写用 Lock
sync.Map(适合低频写、高频读,但不支持遍历和 len,且无泛型约束)sync/atomic(如 atomic.AddInt64、atomic.LoadPointer),零分配、无锁、高效很多数据竞争不是因为不会加锁,而是没意识到要加:
append 不是原子操作,多 goroutine 并发 append 同一个切片会丢数据或 panic-race 编译参数运行程序(go run -race main.go),它能动态检测大部分数据竞争问题