在Golang中,RLock()和Lock()的区别是什么?在使用互斥锁时如何更有效地使用它们?
Lock(): 通过获取锁定,只允许一个goroutine读写。
RLock(): 通过获取锁定,允许多个goroutine同时读取(但不允许写入)。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
a := 0
lock := sync.RWMutex{}
for i := 1; i < 10; i++ {
go func(i int) {
lock.Lock()
fmt.Printf("Lock: from go routine %d: a = %d\n",i, a)
time.Sleep(time.Second)
lock.Unlock()
}(i)
}
b := 0
for i := 11; i < 20; i++ {
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b)
time.Sleep(time.Second)
lock.RUnlock()
}(i)
}
<-time.After(time.Second*10)
}
1) 当一个go-routine已经获得了RLock(),另一个go-routine是否可以获取Lock()进行写操作,还是必须等待RUnlock()?
2) 当有人已经获取了Map的Lock()时,其他go-routine是否可以继续获取RLock()?
3) 假设我们在处理Maps,是否可能出现“并发读写Map”错误?
请参考以下示例以获得更多澄清:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
lock := sync.RWMutex{}
b := map[string]int{}
b["0"] = 0
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["0"])
time.Sleep(time.Second*3)
fmt.Printf("RLock: from go routine %d: lock released\n",i)
lock.RUnlock()
}(1)
go func(i int) {
lock.Lock()
b["2"] = i
fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["2"])
time.Sleep(time.Second*3)
fmt.Printf("Lock: from go routine %d: lock released\n",i)
lock.Unlock()
}(2)
<-time.After(time.Second*8)
fmt.Println("*************************************8")
go func(i int) {
lock.Lock()
b["3"] = i
fmt.Printf("Lock: from go routine %d: b = %d\n",i, b["3"])
time.Sleep(time.Second*3)
fmt.Printf("Lock: from go routine %d: lock released\n",i)
lock.Unlock()
}(3)
go func(i int) {
lock.RLock()
fmt.Printf("RLock: from go routine %d: b = %d\n",i, b["3"])
time.Sleep(time.Second*3)
fmt.Printf("RLock: from go routine %d: lock released\n",i)
lock.RUnlock()
}(4)
<-time.After(time.Second*8)
}
RWMutex是读写互斥锁。该锁可以被任意数量的读取者或单个写入者持有。 RWMutex的零值是未锁定的互斥锁。
在第一次使用后,RWMutex不能被复制。
如果一个goroutine持有RWMutex进行读取,并且另一个goroutine可能调用Lock,则没有goroutine应该期望能够获取读取锁,直到初始读取锁被释放。特别是,这禁止了递归读取锁定。这是为了确保锁最终变得可用;阻塞的Lock调用会排除新的读取者获取锁。
Mutex是互斥锁。Mutex的零值是未锁定的互斥锁。
Go语言提供了通道来实现并发控制,因此我认为最有效的方式不是使用sync.lock,而是使用通道。