[go]浅谈sync.Map

在这里插入图片描述

type Map struct {
	// 保护加锁字段
	mu Mutex
    // readOnly 结构是只读,但其中的操作也有写
	read atomic.Value
	// 最终写入的数据
	dirty map[interface{}]*entry
	// 计数器,每次read没有,读dirty就+1
	misses int
}

type readOnly struct {
	// 只读map
	m map[interface{}]*entry
	// 脏映射中有不在m中的值就true-> dirty被提升了置为false,dirty=nil,true表示上一次已经把read拷贝到dirty,且设置新的值
	amended bool // true if the dirty map contains some key not in m.
}

// expunge 代表 dirty 中被删掉的情况
var expunged = unsafe.Pointer(new(interface{}))

// 存储值的指针
type entry struct {
	p unsafe.Pointer // *interface{}
}

// read里面有key就直接原子读,否则如果dirty!=nil就尝试从dirty读(如果错过次数太多就将dirty提升,设置dirty=nil,amended=false)
func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
	// 尝试从read读readonly对象
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	if !ok && read.amended {
		m.mu.Lock()
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]
		if !ok && read.amended {
			e, ok = m.dirty[key]
			// 标记错过,如果错过次数太多就将dirty提升
			m.missLocked()
		}
		m.mu.Unlock()
	}
	if !ok {
		return nil, false
	}
	// 返回结果
	return e.load()
}

// read里面或者dirty有key就乐观锁或原子更新对应的e.p,否则如果dirty为nil就拷贝read到dirty(amended=false,e.p如果等于nil->expunged),添加k,v到dirty
func (m *Map) Store(key, value interface{}) {
	read, _ := m.read.Load().(readOnly)
	// 如果read里面有就更新read
	if e, ok := read.m[key]; ok && e.tryStore(&value) {
		return
	}
	m.mu.Lock()
	read, _ = m.read.Load().(readOnly)
	// read有且标记为删除 则置为nil,然后添加到dirty中,最后更新read值
	if e, ok := read.m[key]; ok {
		// dirty != nil
		if e.unexpungeLocked() {
			// 添加dirty
			m.dirty[key] = e
		}
		e.storeLocked(&value)
	} else if e, ok := m.dirty[key]; ok { // read没有,dirty中有key就更新v
		e.storeLocked(&value)
	} else {
		// 这个表示dirty可能为nil
		if !read.amended {
			// 将read复制到dirty,同时把nil更改为标记删除
			m.dirtyLocked()
			// 标记dirty不为nil且数据多
			m.read.Store(readOnly{m: read.m, amended: true})
		}
		// dirty中添加value
		m.dirty[key] = newEntry(value)
	}
	m.mu.Unlock()
}

// read中有key则将e.p->nil,否则如果dirty!=nil,去dirty中找并删除key,最后如果这个值存在e.p->nil
func (m *Map) Delete(key interface{}) {
	m.LoadAndDelete(key)
}

// read中有key则将e.p->nil,否则如果dirty中有值,去dirty中找并删除key,最后如果这个值存在e.p->nil
func (m *Map) LoadAndDelete(key interface{}) (value interface{}, loaded bool) {
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	// read中没有且dirty数据多就去dirty中找,然后删除k并增加穿透次数,最后如果有就更新值为nil
	if !ok && read.amended {
		m.mu.Lock()
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]
		if !ok && read.amended {
			e, ok = m.dirty[key]
			delete(m.dirty, key)
			m.missLocked()
		}
		m.mu.Unlock()
	}
	// read中有就尝试把e.p置为nil
	if ok {
		return e.delete()
	}
	return nil, false
}```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值