1、互斥锁
互斥锁是一种常用的控制共享的资源访问的方法,它能够保证同时只有一个 goroutine 可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。
package mainimport ("fmt""sync")func add() {defer wg.Done()//lock.Lock() // 加锁x++//lock.Unlock() // 解锁}var x = 0var wg sync.WaitGroupvar lock sync.Mutex // 定义互斥锁func main() {wg.Add(100)for i := 0; i < 100; i++ {go add() // 启动100个并发}wg.Wait()fmt.Println(x)}
使用互斥锁能够保证同一时间有且只有一个 goroutine 进入临界区,其他的 goroutine 则在等候锁;当互斥锁释放后,等待的 goroutine 才可以获取锁进入临界区, 多个 goroutine 同时等待一个锁时,唤醒的策略是随机的。
2、读写锁
在读多写少的环境中,可以优先使用读写互斥锁(sync.RWMutex),它比互斥锁更加高效。sync包中RWMutex提供了读写互斥锁的封装。
package mainimport ("fmt""sync""time")// 效率对比// 声明读写锁var rwlock sync.RWMutexvar mutex sync.Mutexvar wg sync.WaitGroup// 全局变量var x int// 写数据func write() {//mutex.Lock()rwlock.Lock()x += 1fmt.Println("x",x)time.Sleep(10 * time.Millisecond)//mutex.Unlock()rwlock.Unlock()wg.Done()}func read(i int) {//mutex.Lock()rwlock.RLock()time.Sleep(time.Millisecond)fmt.Println(x)//mutex.Unlock()rwlock.RUnlock()wg.Done()}// 互斥锁执行时间:18533117400// 读写锁执行时间:1312065700func main() {start := time.Now()wg.Add(1)go write()for i := 0; i < 1000; i++ {wg.Add(1)go read(i)}wg.Wait()fmt.Println("运行时间:", time.Now().Sub(start))}
3、map锁
Go语言中内置的map不是并发安全的。
并发读是安全的。
package mainimport ("fmt""sync")func main() {wg := sync.WaitGroup{}m := make(map[int]int)// 添一些假数据for i := 0; i < 5; i++ {m[i] = i*i}// 遍历打印for i := 0; i < 5; i++ {wg.Add(1)go func(x int) {fmt.Println(m[x], "\t")wg.Done()}(i)}wg.Wait()fmt.Println(m)}
并发写则不安全
package mainimport ("fmt""sync")func main() {wg := sync.WaitGroup{}//m := make(map[int]int)var m = sync.Map{}// 并发写for i := 0; i < 100; i++ {wg.Add(1)go func(i int) {defer wg.Done()m.Store(i,i*i)}(i)}wg.Wait()fmt.Println(m.Load(1))fmt.Println(m.Load(2))}
