在Go语言中,实现并发安全主要依赖于以下几个方面:
sync/atomic
包中的AddInt32
, AddInt64
, CompareAndSwapInt32
等。这些函数可以在多个goroutine之间安全地执行加法、减法等操作,而无需使用锁。import (
"fmt"
"sync/atomic"
)
var counter int32
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt32(&counter, 1)
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
}
sync.Mutex
和sync.RWMutex
两种互斥锁,用于在多个goroutine之间同步访问共享资源。互斥锁可以确保同一时间只有一个goroutine访问共享资源,从而避免并发安全问题。import (
"fmt"
"sync"
)
var counter int
var lock sync.Mutex
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
lock.Lock()
counter++
lock.Unlock()
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
}
sync.RWMutex
是一种读写锁,允许多个goroutine同时读取共享资源,但在写入时会阻止其他goroutine访问。这在读操作远多于写操作的场景下可以提高性能。import (
"fmt"
"sync"
)
var data map[string]int
var rwLock sync.RWMutex
func main() {
data = make(map[string]int)
wg := sync.WaitGroup{}
// 写入数据
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := fmt.Sprintf("key%d", i)
value := i * 2
rwLock.Lock()
data[key] = value
rwLock.Unlock()
}(i)
}
// 读取数据
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := fmt.Sprintf("key%d", i)
rwLock.RLock()
value := data[key]
rwLock.RUnlock()
fmt.Printf("Key: %s, Value: %d\n", key, value)
}(i)
}
wg.Wait()
}
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
ch := make(chan int, 10)
// 生产者
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
ch <- i * 2
}(i)
}
// 消费者
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
value := <-ch
fmt.Println("Value:", value)
}()
}
wg.Wait()
}
sync.WaitGroup
, sync.Once
, sync.Cond
等,用于在多个goroutine之间协调执行。总之,Go语言通过原子操作、互斥锁、读写锁、通道和同步原语等多种方式实现了并发安全。在实际开发中,可以根据具体场景选择合适的并发安全策略。