**学习原因**
1、golang面试中可能会遇到
2、之前看过sync.Map的源码,但是记忆很模糊了,重新温习下
**源码分析**
1、设计思想:个人理解是读写分离,在读多写少的情况下,效率较高。
2、源码阅读
```
结构体
type Map struct {
mu Mutex
// read是原子类型。读取数据时,可以不加锁。
// 更新数据时,通过cas不加锁更新read中存在的数据。
read atomic.Value // readOnly
// 操作dirty时,必须持有mutex。有两种状态:
// 1、nil。此时sync.Map保存的所有数据在read中。
// 2、不为nil。此时,dirty保存sync.Map所有的数据,且 dirty存在read中map没有的值。
dirty map[interface{}]*entry
// misses用于记录,dirty中包含read中不存在的值时,read中没命中的次数
// 当 misses == len(dirty)时,用dirty更新 read中的map,并将dirty置为nil
misses int
}
read的底层数据结构
type readOnly struct {
// 和dirty相同的map结构
m map[interface{}]*entry
// true 表示dirty中包含 m中没有的值
amended bool
}
读数据操作 Load函数
func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
// 将read转换为它的底层数据结构
read, _ := m.read.Load().(readOnly)
// 从readOnly结构体中的map读取
e, ok := read.m[key]
// read中不存在,而且dirty中包含read中没有的值
if !ok && read.amended {
m.mu.Lock()
// 加锁,重新从read中读,避免dirty中数据已更新到 read中。
read, _ = m.read.Load().(readOnly)
e, ok = read.m[key]
// read中不存在,而且dirty中包含read中没有的值
if !ok && read.amended {
e, ok = m.dirty[key]
// 只要读了dirty,无论结果,misses+1。
m.missLocked()
}
// 释放锁
m.mu.Unlock()
}
if !ok {
return nil, false
}
return e.load()
}
写操作 Store函数
func (m *Map) Store(key, value interface{}) {
read, _ := m.read.Load().(readOnly)
// read中存在目标key,tryStore:若key未被标记为清除, 用cas更新值。
if e, ok := read.m[key]; ok && e.tryStore(&value) {
return
}
m.mu.Lock() // 加锁
read, _ = m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
// The entry was previously expunged, which implies that there is a
// non-nil dirty map and this entry is not in it.
m.dirty[key] = e
}
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
// dirty已经存在key,直接原子更新对应值
e.storeLocked(&value)
} else {
if !read.amended {
// We're adding the first new key to the dirty map.
// Make sure it is allocated and mark the read-only map as incomplete.
// 此时dirty为nil,第一次向dirty中添加新key-value
m.dirtyLocked()
// 此时dirty包含read中没有的key-value,将amended置为true
m.read.Store(readOnly{m: read.m, amended: true})
}
m.dirty[key] = newEntry(value)
}
m.mu.Unlock()
}
func (m *Map) dirtyLocked() {
// dirty不为空直接返回
if m.dirty != nil {
return
}
read, _ := m.read.Load().(readOnly)
// dirty初始化,长度为read中map的长度
m.dirty = make(map[interface{}]*entry, len(read.m))
// 将read中没标记为清除的key val 放入dirty中
for k, e := range read.m {
if !e.tryExpungeLocked() {
m.dirty[k] = e
}
}
}
```
**以上只是个人理解,如发现错误或其他问题,还请不吝赐教!**
有疑问加站长微信联系(非本文作者))