本文不是 sync.Map 源码详细解读,而是聚焦 entry 的不同状态,特别是 nil 状态和 expunge 状态的区分。

entry 是 sync.Map 存放值的结构体,其值有三种,分别为 value(真正的值)、nil、expunge(任意的指针,标记作用)。如果将其视为一种状态机的话,本文将其三种状态分别称之为value、nil、expunge。

简要概括:

value 状态:entry 里面存放的是真正的值。此时 entry 对应的 key,有三种情况,key 只在 read 中均存在;key 只在 dirty 中存在;在 read 和 dirty 中均存在。

nil 状态:read 中的 key 被删除的时候将其对应的 value(即 entry) p 值设置为 nil。此时 key 只存在 read 中 (ditry 为 nil);在 read 和 dirty 中均存在。

expunge 状态:  此时 key 只存在 read 中而在 dirty 中不存在。

将 sync.Map 抽象为 存、取、删除 三种操作。在这三种操作中来看 entry 状态的改变。

  1、存:对于初始状态的 sync.Map, 一个新键值对 k: A v: A, 首先存放在 dirty 中,此时 entry 为 value 状态,key 只存在 dirty 中。

  2、取:首先 read 中不存在,从 dirty 中取值。数次从 read 中取不中,将 dirty 提升为 read, dirty 被清空。entry 仍为 value 状态,对应的 key 存在于 read 中。

  3、存:另一键值对k:B v:B,存入时,发生 read 向 dirty 拷贝,同时 read 的 amended 标记为 true。此时 key A 存在于 read 和 dirty 中,entry 为 value 状态。

  4、删除:删除 key A,A 的 entry 中 p 值被设置为 nil。此时 key A 存在于 read 和 dirty 中,entry 为 nil 状态。

  5、存:另一键值对k:C v:C。

  6、取:多次读取 key C,触发 dirty 提升为 read,dirty 被清空。此时 key A 只存在于 read 中, entry 为 nil 状态。

  7、存:另一键值对 k:D v:D, 存入时,发生 read 向 dirty 拷贝,key A  的 entry 由 nil 状态转变为 expunge 状态,key A 只存在于 read 中。

  8、取:多次读取 key D,触发 dirty 提升为 read, dirty 被清空,此时 key A 被完全删除。

为什么会用 nil 和 expunge 两种状态来标记一个值的删除?

首先明确,什么时候 expunge 出现。当key A 的值在 read 中为 nil,随后由其他操作触发 read 向 dirty 复制,nil 被转变为 expunge。此时 dirty 不为空,且 key A 在 dirty 中不存在。如果对 key A 重新赋值,修改 read 后,需要同步修改 dirty ,为了保障当 dirty 提升为 read 时,包含所有的值。

再来看 nil 的清空,当 key A 的值为 nil 状态的时候,key A 存在于 read 和 dirty 中或仅存在于 read 中(dirty 为空),因为 read 和 dirty 中相同的 key 指向同一值的指针,因此在这两种情况下,对 key A 重新赋值,均无需考虑 dirty。

golang 标准库 sync.Map 中 nil 和 expunge 区别的更多相关文章

  1. golang 标准库间依赖的可视化展示

    简介 国庆看完 << Go 语言圣经 >>,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内 ...

  2. Golang 标准库log的实现

      原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://gotaly.blog.51cto.com/8861157/1406905 前 ...

  3. golang标准库 context的使用

    本文索引 问题引入 context包简介 示例 问题引入 goroutine为我们提供了轻量级的并发实现,作为golang最大的亮点之一更是备受推崇. goroutine的简单固然有利于我们的开发,但 ...

  4. Go 标准库 —— sync.Mutex 互斥锁

    Mutex 是一个互斥锁,可以创建为其他结构体的字段:零值为解锁状态.Mutex 类型的锁和线程无关,可以由不同的线程加锁和解锁. 方法 func (*Mutex) Lock func (m *Mut ...

  5. Golang 标准库提供的Log(一)

      原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://gotaly.blog.51cto.com/8861157/1405754 G ...

  6. golang标准库分析之net/rpc

    net/rpc是golang提供的一个实现rpc的标准库.

  7. golang 标准库

    前言 不做文字搬运工,多做思路整理 就是为了能速览标准库,只整理我自己看过的...... 最好能看看英文的 标准库 fmt strconv string 跳转 golang知识库总结

  8. STL标准库-容器-map和multimap

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 map与multimap为关联容器,结构如下 map底层实现依然是rb_tree 他的data可以改,但是key不能改,因此ma ...

  9. C 标准库IO缓冲区和内核缓冲区的区别

    1.C标准库的I/O缓冲区          UNIX的传统 是Everything is a file,键盘.显示器.串口.磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也 ...

随机推荐

  1. synology nas

    synology nas synology nas synology nas https://www.synology.cn/zh-cn

  2. aes前台加密后台解密

    aes加密npm地址:https://www.npmjs.com/package/crypto-js aes加密git地址/下载: https://github.com/brix/crypto-js ...

  3. git初始化命令行指引

    Git 全局设置 git config --global user.name "陈耿聪" git config --global user.email "swain@di ...

  4. 深入理解JAVA虚拟机 虚拟机字节码执行引擎

    执行引擎 执行引擎是java虚拟机的重要组成部分.它的作用是接收字节码,解析字节码,执行并输出执行结果. 虚拟机是相对于物理机的概念,物理机的执行引擎是直接建立在处理器.寄存器.指令集和操作系统的层面 ...

  5. Lambda学习总结(一)--函数式接口

    Lambda 表达式是 JDK 1.8 里面的一个重要更新,这意味着 Java 也开始承认了函数式编程,并且尝试引入其中,我们今天就来了解下它的使用. 一.函数式接口 1.1 概念 函数式接口在 Ja ...

  6. UI线程-重绘,回流

    性能消耗大 程序要操作 或 更改界面内容,必须向单一线程执行请求,把这个单一的线程称为事件派发线程,简称为 UI 线程

  7. java.lang.ClassNotFoundException: org.springframework.web.util.WebAppRootListener

    严重: Error configuring application listener of class org.springframework.web.util.WebAppRootListenerj ...

  8. CDOJ 1146 A - 秋实大哥与连锁快餐店 最小生成树 Prim算法 稠密图

    题目链接 A - 秋实大哥与连锁快餐店 Time Limit:3000MS     Memory Limit:65535KB     64bit IO Format:%lld & %llu S ...

  9. (65)CRC32校验C语言版本

    #include<iostream> # include <stdio.h> # include <string.h> typedef unsigned int u ...

  10. lines

    lines Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...