golang 的 sync 包通过 mutex 和 rwmutex 实现线程安全。1. mutex 提供互斥锁,确保同一时间仅一个 goroutine 访问资源;2. rwmutex 提供读写锁,允许多个 goroutine 同时读,但写操作独占;3. 根据读写比例选择锁类型,读多用 rwmutex,否则用 mutex;4. 避免死锁需保持锁顺序一致、避免锁内调用外部函数、使用超时机制;5. 使用 -race 标志检测数据竞争;6. 其他并发工具包括 waitgroup、once、cond 和 atomic 包。正确选择和使用这些工具可实现高效可靠的并发控制。

用 Golang 的
sync
Mutex
RWMutex

sync
Mutex
RWMutex

Mutex (互斥锁)
立即学习“go语言免费学习笔记(深入)”;
Mutex
Mutex
Lock()
Unlock()

package main
import (
"fmt"
"sync"
"time"
)
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock() // 确保函数退出时解锁
c.value++
}
func (c *Counter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
func main() {
counter := Counter{}
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Increment()
}()
}
wg.Wait()
fmt.Println("Counter:", counter.Value()) // 输出:Counter: 1000
}在这个例子中,
Counter
Mutex
value
Increment()
Value()
Lock()
Unlock()
value
defer c.mu.Unlock()
RWMutex (读写锁)
RWMutex
Mutex
RWMutex
RLock()
RUnlock()
Lock()
Unlock()
package main
import (
"fmt"
"sync"
"time"
)
type Data struct {
mu sync.RWMutex
value map[string]int
}
func (d *Data) Read(key string) int {
d.mu.RLock()
defer d.mu.RUnlock()
return d.value[key]
}
func (d *Data) Write(key string, value int) {
d.mu.Lock()
defer d.mu.Unlock()
d.value[key] = value
}
func main() {
data := Data{value: make(map[string]int)}
var wg sync.WaitGroup
// 模拟多个读操作
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
time.Sleep(time.Duration(i) * time.Millisecond) // 模拟不同的读取延迟
fmt.Printf("Reader %d: Value for key 'test' is %d\n", i, data.Read("test"))
}(i)
}
// 模拟一个写操作
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(5 * time.Millisecond) // 稍微等待,确保读操作先执行
data.Write("test", 123)
fmt.Println("Writer: Updated value for key 'test'")
}()
wg.Wait()
}在这个例子中,
Data
RWMutex
map
Read()
RLock()
RUnlock()
map
Write()
Lock()
Unlock()
map
选择 Mutex 还是 RWMutex?
选择
Mutex
RWMutex
RWMutex
Mutex
RWMutex
Mutex
死锁是并发编程中常见的问题,它指的是两个或多个 goroutine 互相等待对方释放锁,导致程序无法继续执行。避免死锁的关键在于避免循环依赖。以下是一些避免死锁的常见技巧:
go vet
go vet
数据竞争指的是多个 goroutine 同时访问和修改同一个共享变量,并且至少有一个 goroutine 是写入操作,这会导致程序出现不可预测的行为。Golang 提供了
-race
-race
go
go run -race main.go
如果程序存在数据竞争,
go
==================
WARNING: DATA RACE
Write at 0x00c0000a2000 by goroutine 7:
main.Counter.Increment()
/path/to/your/code/main.go:15 +0x45
Previous write at 0x00c0000a2000 by goroutine 6:
main.Counter.Increment()
/path/to/your/code/main.go:15 +0x45
Goroutine 7 (running) created at:
main.main()
/path/to/your/code/main.go:28 +0x9b
Goroutine 6 (running) created at:
main.main()
/path/to/your/code/main.go:28 +0x9b
==================这个报告会告诉你数据竞争发生的位置、涉及的 goroutine 以及相关的代码行数,帮助你快速定位和修复问题。
除了
Mutex
RWMutex
sync
sync.WaitGroup
sync.Once
sync.Cond
atomic
选择合适的并发控制工具取决于你的具体需求。例如,如果你需要等待一组 goroutine 完成,可以使用
sync.WaitGroup
sync.Once
sync.Cond
atomic
理解并熟练运用这些并发控制工具,可以帮助你编写出高效、可靠的并发程序。
以上就是如何用Golang的sync包实现线程安全 剖析Mutex和RWMutex的使用技巧的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号