sync包文档:Package sync - The Go Programming Language
sync包提供了基本同步的操作,如互斥锁等。除了Once和 WaitGroup之外,大多数类型都是提供低级库例程使用的。而更高级的的同步最好是通过channel和通信来完成。
互斥锁比较暴力,当一个goroutine获得了互斥锁之后,其他的goroutine只能等待释放锁。
使用互斥锁时,对资源操作完一定要解锁,否则程序会死锁。建议使用defer语句来解锁。
- //定义互斥锁对象
- var mutex_name sync.Mutex
-
- //上锁
- mutex_name.Lock()
- //解锁
- mutex_name.Unlock()
同样是的火车站售票问题,我们看一下通过互斥锁解决临界资源问题的效果
- //车票余量
- var tickets = 5
-
- //定义同步等待组
- var wg sync.WaitGroup
-
- //定义互斥锁对象
- var mutex sync.Mutex
-
- func main() {
- wg.Add(3)
- go saleTickets("1号售票口")
- go saleTickets("2号售票口")
- go saleTickets("3号售票口")
- wg.Wait()
- }
-
- func saleTickets(name string) {
- for {
- mutex.Lock()
- if tickets > 0 {
- fmt.Printf("车票剩余:%v, %v售出\n", tickets, name)
- tickets--
- time.Sleep(1 * time.Second)
- } else {
- mutex.Unlock()
- fmt.Println("车票已售罄...")
- wg.Done()
- break
- }
- mutex.Unlock()
- }
- }

读写锁和普通的互斥锁不同的是,它是一种专门针对读操作和写操作的互斥锁。
读写锁同一时刻允许有多个读操作在进行,但在同一时刻只允许有一个写操作在进行。并且在某一个写操作进行过程中,读操作也是不可以进行的。所以说,读写锁对于读操作可以同时并发,但是对于写操作是完全互斥的。
- //定义读写锁锁对象
- var rwmutex_name sync.RWMutex
-
- //读锁
- rwmutex_name.RLock
- //读解锁
- rwmutex_name.RUnlock
-
- //写锁
- rwmutex_name.Lock
- //写解锁
- rwmutex_name.Unlock
读写锁我们就不进行示例的展示了,因为和上面互斥锁展示的示例效果应该差别不大。
对写锁实际解决的问题是,使用互斥锁带来并发能力降低的问题。因为互斥锁不论读操作还是写操作都会阻塞,程序从并发变成了串行。
而实际上对于不会对临界资源产生修改的读操作,我们是不需要阻塞的;只有对临界资源需要修改的写操作,我们才需要阻塞。所以读写锁就是为了提高程序加锁时的并发能力。