1.理解线程安全
现在计算机体系中大部分都是多核计算机,都是包含有多个cpu.
当两个线程同时访问同一段内存,CPU的速度是比内存的速度快很多,在现在的CPU架构上,每个CPU都有自己的缓存机制,如同线程1和线程2 刚开始都去访问内存key = value1,cpu1和cpu2读内存只有第一次才会去访问内存,然后把数据存放在CPU缓存中,这就导致了,在某一时间点,CPU1修改了变量,但是CPU2没有缓存的变量还没变,导致变量不同步,会造成线程安全。
2.通过加锁解决线程问题
锁:是用来保护一个变量的访问,加锁后,只有一个线程可以读取数据,在未释放锁之前,其余线程是不能访问和操作这份数据的
- go语言不仅仅提供基于CSP的通讯模型,也支持基于共享内存的多线程数据访问
- Sync包提供了锁的基本原语
- sync.Mutex互斥锁
- Lock()加锁, Unlock() 解锁
- sync.RWMutex 读写分离锁 (一定程度上提高了性能)
- 不限制并发读取数据,只限制并发写操作和并发读写操作
- sync.WaitGroup
- 等待一组goroutine返回
-
func waitByWg() { wg := sync.WaitGroup{} wg.Add(delta:100) //创建一百个线程 for i := 0; i< 100; i++ { go func(i int ) { fmt.Println(i) wg.Done() //每一个线程执行完成后都需要done }(i) } wg.Wait() // 只有当一百个线程全部运行完成后才会退出 }
- sync.Once
- 保证某段代码只执行一次
- sync.Cond
- 让一组goroutine在满足特定条件时被唤醒