Golang map套指针安全吗

来源:个人站长作者:小鱼头衔:草根站长
导读:本期聚焦于小伙伴创作的《Golang map套指针安全吗》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Golang map套指针安全吗》有用,将其分享出去将是对创作者最好的鼓励。

在Golang开发中,map是常用的数据结构,很多场景下我们会将指针作为map的value存储,比如存储结构体指针、切片指针等。这种map套指针的用法是否安全,需要从map本身的特性和指针的特性两方面来分析。

Golang map套指针安全吗

map的基础并发特性

Golang内置的map不是并发安全的数据结构,官方明确说明普通map在多个goroutine同时读写时会触发fatal error。即使map的value是普通值类型,并发读写也会导致程序崩溃,更不用说嵌套指针的场景。

下面是一段并发读写普通map的示例代码,会直接触发运行时错误:

package main

import (
    "fmt"
    "time"
)

func main() {
    m := make(map[int]int)
    // 启动写goroutine
    go func() {
        for i := 0; i < 1000; i++ {
            m[i] = i
        }
    }()
    // 启动读goroutine
    go func() {
        for i := 0; i < 1000; i++ {
            fmt.Println(m[i])
        }
    }()
    time.Sleep(time.Second)
}

map套指针的额外风险

除了map本身的并发不安全问题,嵌套指针还会带来以下额外风险:

1. 指针悬空风险

如果map中存储的指针指向的对象已经被释放,或者指针指向的变量已经离开作用域,此时通过map获取指针并解引用,就会访问无效内存,导致程序崩溃或者数据错误。

示例代码如下:

package main

import "fmt"

func getPointer() *int {
    num := 10
    return &num // 返回局部变量指针,函数结束后num的内存可能被回收
}

func main() {
    m := make(map[string]*int)
    m["test"] = getPointer()
    // 此时m["test"]指向的内存可能已经无效
    fmt.Println(*m["test"])
}

2. 指针指向的数据并发修改风险

即使我们通过加锁保证了map的读写安全,如果多个goroutine拿到同一个指针并修改其指向的内容,依然会出现数据竞争问题,因为指针指向的是同一块内存区域。

package main

import (
    "fmt"
    "sync"
)

type User struct {
    Name string
    Age  int
}

func main() {
    m := make(map[int]*User)
    m[1] = &User{Name: "Tom", Age: 18}
    var wg sync.WaitGroup
    wg.Add(2)
    // 第一个goroutine修改Age
    go func() {
        defer wg.Done()
        m[1].Age = 20
    }()
    // 第二个goroutine读取Age
    go func() {
        defer wg.Done()
        fmt.Println(m[1].Age)
    }()
    wg.Wait()
}

如何安全使用map套指针

要避免上述问题,可以采取以下方案:

  • 如果需要在并发场景使用map,优先使用sync.Map,它内置了并发安全机制,适合读多写少的场景。
  • 如果必须使用普通map,需要配合sync.RWMutex对map的读写操作加锁,保证同一时间只有一个goroutine修改map结构。
  • 存储指针时,确保指针指向的对象生命周期长于map的使用周期,避免返回局部变量指针,或者存储已经被释放的对象指针。
  • 如果多个goroutine需要修改指针指向的内容,需要对指针指向的对象也加锁,或者使用值类型存储,避免共享内存修改冲突。

下面是使用sync.RWMutex保证map套指针并发安全的示例:

package main

import (
    "fmt"
    "sync"
)

type User struct {
    Name string
    Age  int
}

func main() {
    var (
        m     = make(map[int]*User)
        mutex sync.RWMutex
        wg    sync.WaitGroup
    )
    wg.Add(2)
    // 写操作加写锁
    go func() {
        defer wg.Done()
        mutex.Lock()
        m[1] = &User{Name: "Tom", Age: 18}
        mutex.Unlock()
    }()
    // 读操作加读锁
    go func() {
        defer wg.Done()
        mutex.RLock()
        user := m[1]
        mutex.RUnlock()
        if user != nil {
            fmt.Println(user.Name, user.Age)
        }
    }()
    wg.Wait()
}

总结

map套指针本身不是绝对不安全,核心风险来自两方面:一是map本身的并发读写不安全特性,二是指针带来的内存管理和共享修改问题。只要我们在合适的场景下选择对应的并发控制方案,合理管理指针的生命周期,就可以安全地使用这种结构。如果不需要并发场景,且指针指向的对象生命周期可控,map套指针是完全可以正常使用的。

Golangmap指针并发安全修改时间:2026-07-09 01:18:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。