func(m *Map) Swap(key, value any) (previous any, loaded bool) { read := m.loadReadOnly() // 是否已经有记录了 if e, ok := read.m[key]; ok { // 尝试存储,存储成功了就直接返回 if v, ok := e.trySwap(&value); ok { if v == nil { returnnil, false } return *v, true } }
// 没存成功 或者 没有这个数据 m.mu.Lock() // 加锁再读(防止这段时间有人修改 read = m.loadReadOnly() if e, ok := read.m[key]; ok { if e.unexpungeLocked() { // 如果 unexpungeLocked 为 true,直接值覆盖 // m.dirty 不会为 nil // 这是因为为 true 的条件是调用了 dirtyLocked ,此时 dirty 一定不为 nil m.dirty[key] = e } // 加锁且赋值 if v := e.swapLocked(&value); v != nil { loaded = true previous = *v } } elseif e, ok := m.dirty[key]; ok { // 如果在 dirty 找到了,那么直接覆盖值 if v := e.swapLocked(&value); v != nil { loaded = true previous = *v } } else { // 这里是 dirty 为 nil 的情况 if !read.amended { // 下面会说 dirtyLocked 的源码 // 简单来说就是将 m 的键值复制一份 m.dirtyLocked() // 修改属性 m.read.Store(&readOnly{m: read.m, amended: true}) } // 然后往 dirty 写入 m.dirty[key] = newEntry(value) } // 释放锁 m.mu.Unlock() return previous, loaded }
上面的一些函数
tryExpungeLocked
1 2 3 4 5 6 7 8 9 10 11 12
func(e *entry) tryExpungeLocked() (isExpunged bool) { p := e.p.Load() // 循环判断当前值是否是被删除的 for p == nil { if e.p.CompareAndSwap(nil, expunged) { // 是被删除的,置为 nil,返回 true returntrue } p = e.p.Load() } return p == expunged }