You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go包级变量替换是否线程安全?附代码示例分析

package maptest

var oldMap = map[string]string{"key1": "old_value1", "key2": "old_value2", "key3": "old_value3"}

func updateMap() {
    oldMap = map[string]string{"key1": "new_value1", "key2": "new_value2", "key3": "new_value3"}
}

func action1() string {
    return oldMap["key1"]
}

func action2() {
    var resultKey string
    var resultValue string

    for k, v := range oldMap {
        resultKey += oldMap[k]
        resultValue += v
    }
}

问题1解答

不会引发panic,action1()要么返回旧值要么返回新值,不会出现中间状态。

原因是:oldMap作为map类型本质是一个指针,updateMap()的操作是给这个指针变量赋一个新的map地址,这种单个机器字的赋值操作在Go中是原子性的——CPU会一次性完成赋值,不会出现指针只修改一半的无效状态。所以action1()读取oldMap时,要么拿到旧map的指针,要么拿到新map的指针,只会返回对应map里key1的有效值,不会触发panic。

问题2解答

执行过程中会出现resultKey和resultValue拼接内容来自不同map的情况,你的假设基本正确:

  • 当updateMap()被调用后,后续循环里的oldMap[k]会访问新map,但v依然是旧map中对应键的value副本。
  • 使用v是完全安全的:因为string是值类型,v是遍历旧map时已经复制到栈上的具体值,和旧map是否被回收无关,肯定能拿到旧map里的正确数据。
  • 但resultKey的取值会出问题:循环开始时,range是基于旧map的引用遍历键,但每次循环里的oldMap[k]是读取当前oldMap变量指向的map——如果updateMap()已经替换了oldMap的引用,这里就会取新map的k对应值,和v可能完全不匹配。比如旧map的key1对应old_value1(赋值给v),但新map的key1是new_value1,此时resultKey会拼接new_value1,而resultValue拼接old_value1。
  • 整个过程不会panic,因为没有并发修改同一个map:旧map只是不再被引用,没有被修改;新map也只是被读取,没有修改操作,不会触发map并发读写的panic。

内容的提问来源于stack exchange,提问作者ragarac3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 19:47:25