前言

最近一个群里看到一个有趣的八股文,问题是:使用context携带的value是线程安全的吗?这道题其实就是考察面试者对context实现原理的理解,如果不知道context的实现原理,很容易答错这道题,所以本文我们就借着这道题,再重新理解一遍context携带value的实现原理。

context携带value是线程安全的吗?

先说答案,context本身就是线程安全的,所以context携带value也是线程安全的,写个简单例子验证一下:

func main()  {ctx := context.WithValue(context.Background(), "asong", "test01")go func() {for {_ = context.WithValue(ctx, "asong", "test02")}}()go func() {for {_ = context.WithValue(ctx, "asong", "test03")}}()go func() {for {fmt.Println(ctx.Value("asong"))}}()go func() {for {fmt.Println(ctx.Value("asong"))}}()time.Sleep(10 * time.Second)
}

程序正常运行,没有任何问题,接下来我们就来看一下为什么context是线程安全的!!!

为什么线程安全?

context包提供两种创建根context的方式:

  • context.Backgroud()

  • context.TODO()

又提供了四个函数基于父Context衍生,其中使用WithValue函数来衍生context并携带数据,每次调用WithValue函数都会基于当前context衍生一个新的子contextWithValue内部主要就是调用valueCtx类:

func WithValue(parent Context, key, val interface{}) Context {if parent == nil {panic("cannot create context from nil parent")}if key == nil {panic("nil key")}if !reflectlite.TypeOf(key).Comparable() {panic("key is not comparable")}return &valueCtx{parent, key, val}
}

valueCtx结构如下:

type valueCtx struct {Contextkey, val interface{}
}

valueCtx继承父Context,这种是采用匿名接口的继承实现方式,key,val用来存储携带的键值对。

通过上面的代码分析,可以看到添加键值对不是在原context结构体上直接添加,而是以此context作为父节点,重新创建一个新的valueCtx子节点,将键值对添加在子节点上,由此形成一条context链。

获取键值过程也是层层向上调用直到最终的根节点,中间要是找到了key就会返回,否会就会找到最终的emptyCtx返回nil。画个图表示一下:

image-20220207214507921

总结:context添加的键值对一个链式的,会不断衍生新的context,所以context本身是不可变的,因此是线程安全的。

总结

本文主要是想带大家回顾一下context的实现原理,面试中面试官都喜欢隐晦提出问题,所以这就需要我们有很扎实的基本功,一不小心就会掉入面试官的陷阱,要处处小心哦~

好啦,本文到这里就结束了,我们下期见。

Go 的 Contex 是线程安全的吗?相关推荐

  1. 多线程编程指南 part 2

    多线程编程指南 Sun Microsystems, Inc. 4150 Network Circle Santa Clara, CA95054 U.S.A. 文件号码819–7051–10 2006 ...

  2. 并发编程-06线程安全性之可见性 (synchronized + volatile)

    文章目录 线程安全性文章索引 脑图 可见性定义 导致不可见的原因 可见性 -synchronized (既保证原子性又保证可见性) 可见性 - volatile(但不保证操作的原子性) volatil ...

  3. win32 c语言创建线程,【原创】win32线程及线程内核对象

    内核对象与GDI对象 GDI对象: 1. DC 2. 画笔 3. 画刷 内核对象 1. 进程 process 2. 线程 thread 3. 文件 file 4. 事件 envent 5. 信号量 s ...

  4. io_uring 触发内核线程的问题 iou-wrk 线程 io_uring 原理 io_uring SQPOLL 原理

    (这里归档到胡思乱想就是不是作为容易查看的技术博客文章存在,给自己归档一下) 2022.04.07 io_uring 内部的实现是 poll(feat_fast_poll),线程池(iou-wrk-x ...

  5. java 手编线程池_死磕 java线程系列之自己动手写一个线程池

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...

  6. Redis 笔记(12)— 单线程架构(非阻塞 IO、多路复用)和多个异步线程

    Redis 使用了单线程架构.非阻塞 I/O .多路复用模型来实现高性能的内存数据库服务.Redis 是单线程的.那么为什么说是单线程呢? Redis 在 Reactor 模型内开发了事件处理器,这个 ...

  7. Python 多线程总结(2)— 线程锁、线程池、线程数量、互斥锁、死锁、线程同步

    主要介绍使用 threading 模块创建线程的 3 种方式,分别为: 创建 Thread 实例函数 创建 Thread 实例可调用的类对象 使用 Thread 派生子类的方式 多线程是提高效率的一种 ...

  8. 详解 Tomcat 的连接数与线程池

    原文出处:编程迷思 前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文 ...

  9. Spring并发访问的线程安全性问题

    下面的记录对spring中并发的总结.理论分析参考Spring中Singleton模式的线程安全,建议先看 spring中的并发访问题: 我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下 ...

最新文章

  1. 特斯拉“国王”王权不保
  2. 洪小文:以科学的方式赤裸裸地剖析AI(二)|从寒冬到复兴
  3. [C#]关于Access的“INSERT INTO 语句的语法错误”问题
  4. python提取字符串中的 中文 日文 韩文
  5. 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1099:第n小的质数
  6. python图片内容长度识别_Python实现识别图片内容的方法分析
  7. ODPS2.0重装上阵,优化提升SQL语言表达能力
  8. php 代码下载_PHP实现下载功能的代码
  9. php自动滚动到页尾,让DOM元素自动滚到视野内ScrollIntoView
  10. 浮动特性-脱标(HTML、CSS)
  11. python selenium page object_Selenium Page Object 自动化测试框架-Page Object设计
  12. 自定义 feign 调用实现 hystrix 超时、异常熔断
  13. uniapp 微信浏览器H5页面自定义分享链接
  14. 局域网文件传输方式分析
  15. 各代iphone尺寸_iPhone每一代的屏幕尺寸比例是多少?
  16. Linux下tftp服务器/客户端安装
  17. 对象数组中根据某个属性名的值相同,求某一项的和。
  18. WindowsPE无法安装系统
  19. ESXI自动关机 ping值检测关机脚本
  20. 信息熵、相对熵和交叉熵

热门文章

  1. 高可用之KeepAlived(2):keepalived+lvs
  2. Android 使用webview遇到的问题及解决办法
  3. 启动NASA“造导弹”,阿里为何要“上天”?
  4. memcached常用命令
  5. 证明randomized quicksort的平均running time为nlgn 的数学过程
  6. 为什么统计学家应该关注数据挖掘
  7. 利用权限禁止QQ的自动升级(QQUpdateCenter)
  8. (十五) 构建springmvc+mybatis+dubbo分布式平台-window安装dubbo管控台
  9. iOS 怎么设置 UITabBarController 的第n个item为第一响应者?
  10. 美团搜索-搜索引擎关键字智能提示的一种实现[转]