互斥锁

互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。

定义一个锁:

var lock sync.Mutex

加锁:

lock.Lock()

解锁:

lock.Unlock()

完整示例

package main
 
import (
	"fmt"
	"sync"
)
 
func main() {
	var lock sync.Mutex
	var wg sync.WaitGroup
	x := 0
	//  开100个goroutine
	for i := 0; i < 100; i++ {
		//  计数
		wg.Add(1)
		go func() {
			//  锁了之后其它goroutine不能对x进行操作
			lock.Lock()
			for j := 0; j < 100; j++ {
				x += 1
			}
			//  解锁
			lock.Unlock()
			//  执行完毕
			wg.Done()
		}()
	}
	//  等待所有goroutine执行完毕
	wg.Wait()
	//  输出x(10000)
	fmt.Println(x)
}

读写互斥锁

互斥锁是完全互斥的,但是有很多实际的场景下是读多写少的,当并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。 读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。

定义一个读写锁:

var rwlock sync.RWMutex

加写锁:

rwlock.Lock()

解写锁:

rwlock.Unlock()

加读锁:

rwlock.RLock()

解读锁:

rwlock.RUnlock()

完整示例

package main
 
import (
	"fmt"
	"sync"
)
 
func main() {
	var rwlock sync.RWMutex
	var wg sync.WaitGroup
	x := 0
	wg.Add(1)
	//  读x
	go func() {
		for a := 0; a < 100; a++ {
			//  读锁
			rwlock.RLock()
			fmt.Println(x)
			//  解读锁
			rwlock.RUnlock()
		}
		wg.Done()
	}()
	//  开100个goroutine写入x
	for i := 0; i < 100; i++ {
		//  计数
		wg.Add(1)
		go func() {
			//  写锁
			rwlock.Lock()
			for j := 0; j < 100; j++ {
				x += 1
			}
			//  解写锁
			rwlock.Unlock()
			//  执行完毕
			wg.Done()
		}()
	}
	//  等待所有goroutine执行完毕
	wg.Wait()
}

运行后可发现每次读操作输出的结果,都相差100,因为写锁在解开前不能进行读操作,因此只有等x加上100后才能读,而读锁在解开前不能进行写操作,因此每次读的时候x不能修改。