并发安全和锁
1. sync.Mutex—实现互斥锁
var lock sync.Mutex
var x int
func add() { //这样,在多个goroutine同时访问x时,才不会造成x错误for i := 0; i < 5000; i++ {lock.Lock() // 加锁x = x + 1lock.Unlock() // 解锁}
}
2. sync.RWMutex—实现读写互斥锁
读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。
var rwlock sync.RWMutex
rwlock.Lock() // 加写锁
rwlock.Unlock() // 解写锁
rwlock.RLock() // 加读锁
rwlock.RUnlock() // 解读锁
3. sync.WaitGroup—实现并发任务的同步
sync.WaitGroup返回一个非引用类型对象(维护一个计数器,计数器为0时,Wait()才会让函数继续向下运行)
func f(i int, wg *sync.WaitGroup) {fmt.Println(i)wg.Done() //Done每次将计数器-1
}func main() {wg := sync.WaitGroup{}wg.Add(100) //计数器初值设置为100for i := 0; i < 100; i++ {go f(i, &wg) //开启一个并行线程}wg.Wait() //计数器为0时才会继续运行后续程序,否则拦截
}
4. sync.Once—实现唯一初始化
var once sync.Once
once.Do(初始化函数); //do实际上就是互斥锁+布尔变量,保证这个方法只会被安全的执行一次//例如下面我们使用Once实现单例模式:
type singleton struct {}var instance *singleton
var once sync.Oncefunc GetInstance() *singleton {once.Do(func() {instance = &singleton{}})return instance
}
5. sync.Map—实现并发安全的Map
操作 | 作用 |
---|---|
var m = sync.Map{} | 初始化 |
m.Store(key, n) | 存入键值对 |
value, _ := m.Load(key) | 取出键值对 |
Delete(key) | 删除键值对 |
6. sync/atomic—实现原子操作
函数 | 作用 |
---|---|
func AddInt32(addr *int32, delta int32) (new int32) | 加操作 |
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) | 比较old==new,为否则将new存入addr |
func SwapInt32(addr *int32, new int32) (old int32) | 直接将new存入addr |
func LoadInt32(addr *int32) (val int32) | 读取addr下的变量值 |
func StoreInt32(addr *int32, val int32) | 将val存入addr下 |