- 使用互斥锁(Mutex)
- 互斥锁是一种常用的同步工具,用于保护共享资源。在Go语言中,
sync.Mutex
可以实现这一功能。
- 当一个函数需要访问共享资源时,它首先获取互斥锁,在访问完成后释放互斥锁,这样其他函数在同一时间就无法访问该资源。
- 示例代码如下:
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func increment(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait()
fmt.Println("Final counter value:", counter)
}
- 读写锁(RWMutex)
- 如果共享资源的读取操作远远多于写入操作,可以使用读写锁。
sync.RWMutex
允许同一时间有多个读操作,但只允许一个写操作。
- 读操作使用
RLock
方法获取锁,写操作使用Lock
方法获取锁。
- 示例代码如下:
package main
import (
"fmt"
"sync"
)
var (
data int
rwmu sync.RWMutex
)
func read(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.RLock()
fmt.Println("Read data:", data)
rwmu.RUnlock()
}
func write(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.Lock()
data++
fmt.Println("Write data:", data)
rwmu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go read(&wg)
}
for i := 0; i < 2; i++ {
wg.Add(1)
go write(&wg)
}
wg.Wait()
}
- 使用通道(Channel)
- 通道是Go语言中用于在不同的goroutine之间进行通信的机制。通过将共享资源的访问封装在通道操作中,可以避免显式地使用锁。
- 示例代码如下:
package main
import (
"fmt"
"sync"
)
type Counter struct {
value int
}
func newCounter() *Counter {
return &Counter{}
}
func (c *Counter) increment(ch chan struct{}) {
<-ch
c.value++
ch <- struct{}{}
}
func (c *Counter) get(ch chan struct{}) int {
<-ch
v := c.value
ch <- struct{}{}
return v
}
func main() {
var wg sync.WaitGroup
counter := newCounter()
ch := make(chan struct{}, 1)
ch <- struct{}{}
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.increment(ch)
}()
}
wg.Wait()
fmt.Println("Final counter value:", counter.get(ch))
close(ch)
}
- 使用
sync.Map
sync.Map
是Go 1.9引入的一个线程安全的映射。它适用于高并发读写的场景,无需额外的锁机制。
- 示例代码如下:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var m sync.Map
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
m.Store(n, n*n)
}(i)
}
go func() {
wg.Wait()
m.Range(func(key, value interface{}) bool {
fmt.Printf("Key: %d, Value: %d\n", key, value)
return true
})
}()
wg.Wait()
}