golang读写锁保证线程安全

什么时候需要用到锁

互斥锁

互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个 goroutine 可以访问到共享资源(同一个时刻只有一个线程能够拿到锁)

先通过一个并发读写的例子演示一下,当多线程同时访问全局变量时,结果会怎样?

package main
import ("fmt")
 
var count int
 
func main() {
    for i := 0; i < 2; i++ {
        go func() {
            for i := 1000000; i > 0; i-- {
                count ++
            }
            fmt.Println(count)
        }()
    }
 
    fmt.Scanf("\n")  //等待子线程全部结束
}
 
运行结果:
980117
1011352  //最后的结果基本不可能是我们想看到的:200000

修改代码,在累加的地方添加互斥锁,就能保证我们每次得到的结果都是想要的值

package main
import ("fmt"
    "sync"
)

var (
    count int
    lock sync.Mutex
)

func main() {
    for i := 0; i < 2; i++ {
        go func() {
            for i := 1000000; i > 0; i-- {
                lock.Lock()
                count ++
                lock.Unlock()
            }
            fmt.Println(count)
        }()
    }

    fmt.Scanf("\n")  //等待子线程全部结束
}

运行结果:
1952533
2000000  //最后的线程打印输出

读写锁(sync.RWMutex)

在读多写少的环境中,可以优先使用读写互斥锁(sync.RWMutex),它比互斥锁更加高效。sync 包中的 RWMutex 提供了读写互斥锁的封装

读写锁分为:读锁和写锁

  • 如果设置了一个写锁,那么其它读的线程以及写的线程都拿不到锁,这个时候,与互斥锁的功能相同
  • 如果设置了一个读锁,那么其它写的线程是拿不到锁的,但是其它读的线程是可以拿到锁

通过设置写锁,同样可以实现数据的一致性:

package main
import ("fmt"
    "sync"
)
 
var (
    count int
    rwLock sync.RWMutex
)
 
func main() {
    for i := 0; i < 2; i++ {
        go func() {
            for i := 1000000; i > 0; i-- {
                rwLock.Lock()
                count ++
                rwLock.Unlock()
            }
            fmt.Println(count)
        }()
    }
 
    fmt.Scanf("\n")  //等待子线程全部结束
}
 
运行结果:
1968637
2000000

你可能感兴趣的:(#,golang)