在Golang中,为了保证多个goroutine之间的线程安全性,我们需要使用sync.Mutex或sync.RWMutex。
sync.Mutex是一种互斥锁,它可以用于保护共享资源。在某个goroutine获取Mutex锁之后,其他goroutine会被阻塞,直到该goroutine释放Mutex锁。这样可以避免多个goroutine同时访问共享资源造成竞态条件的出现。
下面是一个示例程序,演示如何使用sync.Mutex实现多个goroutine对共享变量进行操作的线程安全:
package main
import (
"fmt"
"sync"
)
var count int
var mutex sync.Mutex // 定义一个Mutex对象
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mutex.Lock() // 获取锁
count++
fmt.Println(count)
mutex.Unlock() // 释放锁
}()
}
wg.Wait()
}
在这个示例中,我们定义了一个全局变量count,并创建了一个Mutex对象mutex。然后我们启动了10个goroutine,它们会尝试对count进行加1操作。在每个goroutine中,首先需要获取Mutex锁,然后进行加1操作,最后释放Mutex锁。
由于Mutex是一个排他锁,当一个goroutine获取了Mutex锁并进行操作时,其他goroutine会被阻塞,直到该goroutine释放Mutex锁。这样可以保证多个goroutine之间对共享变量的访问是线程安全的。
除了Mutex,Golang还提供了另一种锁——RWMutex。它是读写互斥锁,允许多个goroutine同时读取共享资源,并在某个goroutine需要写入时阻塞其他goroutine的读或写操作。
下面是一个示例程序,演示如何使用sync.RWMutex实现多个goroutine对共享变量进行读和写的线程安全:
package main
import (
"fmt"
"sync"
)
var count int
var rwMutex sync.RWMutex // 定义一个RWMutex对象
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rwMutex.RLock() // 获取读锁
fmt.Println(count) // 读取count变量
rwMutex.RUnlock() // 释放读锁
}()
}
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rwMutex.Lock() // 获取写锁
count++
fmt.Println(count) // 修改并输出count变量
rwMutex.Unlock() // 释放写锁
}()
}
wg.Wait()
}
在这个示例中,我们定义了一个全局变量count,并创建了一个RWMutex对象rwMutex。然后我们启动了10个goroutine,它们会尝试对count进行读取操作。在每个goroutine中,首先需要获取读锁,然后进行读取操作,最后释放读锁。
另外,我们还启动了5个goroutine,它们会尝试对count进行加1操作。在每个goroutine中,首先需要获取写锁,然后进行加1操作,最后释放写锁。
由于RWMutex是一个读写互斥锁,因此在多个goroutine同时读取共享资源时不会阻塞,但在有一个goroutine需要写入时会阻塞其他goroutine的读或写操作。这样可以保证多个goroutine之间对共享变量的访问是线程安全的。