企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
> 在并发的情况下,多个线程或协程同时去修改同一变量。使用锁能保证在某一时间点内,只有一个协程或线程修改这一变量 ## 互斥锁 > 并发程序中最使用互斥锁方式,当有一个 goroutine 获得互斥锁,其他的互斥锁都将阻塞等待其解锁后才能执行 ~~~ package main import ( "fmt" "sync" "time" ) func main() { var mutex sync.Mutex count := 0 for i := 0; i < 50; i++ { go func() { mutex.Lock() //defer mutex.Unlock() count += 1 mutex.Unlock() }() } // 主协程停留一下,好让子协程都计算完 time.Sleep(time.Second) fmt.Println("the count is : ", count) } ~~~ ## 读写锁 > 当有一个 goroutine 获得写锁定,其它无论是读锁定还是写锁定都将阻塞直到写解锁; > 当有一个 goroutine 获得读锁定,其它读锁定仍然可以继续;当有一个或任意多个读锁定,写锁定将等待所有读锁定解锁之后才能够进行写锁定。所以说这里的读锁定(RLock)目的其实是告诉写锁定:有很多人正在读取数据,你给我站一边去,等它们读(读解锁)完你再来写(写锁定) ~~~ # 写操作的锁定和解锁 * func (*RWMutex) Lock * func (*RWMutex) Unlock # 读操作的锁定和解锁 * func (*RWMutex) Rlock * func (*RWMutex) RUnlock ~~~ > 示例 ~~~ package main import ( "fmt" "math/rand" "sync" ) var count int var rw sync.RWMutex func main() { ch := make(chan struct{}, 10) for i := 0; i < 5; i++ { go read(i, ch) } for i := 0; i < 5; i++ { go write(i, ch) } for i := 0; i < 10; i++ { <-ch } } func read(n int, ch chan struct{}) { rw.RLock() fmt.Printf("goroutine %d 进入读操作...\n", n) v := count fmt.Printf("goroutine %d 读取结束,值为:%d\n", n, v) rw.RUnlock() ch <- struct{}{} } func write(n int, ch chan struct{}) { rw.Lock() fmt.Printf("goroutine %d 进入写操作...\n", n) v := rand.Intn(1000) count = v fmt.Printf("goroutine %d 写入结束,新值为:%d\n", n, v) rw.Unlock() ch <- struct{}{} } ~~~ > 结果 > 从该例子中,我们可以直观的看到,当goroutine 获得写锁定,其他的读或写锁定都将阻塞,而goroutine 获得读锁定时,其他的读锁定照常执行,只有写锁定被阻塞 ~~~ goroutine 4 进入写操作... goroutine 4 写入结束,新值为:81 goroutine 4 进入读操作... goroutine 4 读取结束,值为:81 goroutine 2 进入读操作... goroutine 2 读取结束,值为:81 goroutine 0 进入读操作... goroutine 0 读取结束,值为:81 goroutine 3 进入读操作... goroutine 3 读取结束,值为:81 goroutine 1 进入读操作... goroutine 1 读取结束,值为:81 goroutine 1 进入写操作... goroutine 1 写入结束,新值为:887 goroutine 2 进入写操作... goroutine 2 写入结束,新值为:847 goroutine 3 进入写操作... goroutine 3 写入结束,新值为:59 goroutine 0 进入写操作... goroutine 0 写入结束,新值为:81 ~~~