Golang - string 是否线程安全
线程安全是什么
线程安全是指在多线程环境下,程序的执行能够正确地处理多个线程并发访问共享数据的情况,保证程序的正确性和可靠性。
type StringHeader struct {
Data uintptr //存放指针,其指向具体的存储数据的内存区域
Len int //字符串的长度
}
并发访问
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
str := "脑子进煎鱼了"
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println(str)
}()
}
wg.Wait()
}
定义了一个 string 变量 str,然后启动了 5 个 goroutine,每个 goroutine 都会输出 str 的值。由于 str 是不可变类型,因此在多个 goroutine 中并发访问它是安全的。
不可变类型,指的是一种不能被修改的数据类型,也称为值类型(value type)。不可变类型在创建后其值不能被改变,任何对它的修改操作都会返回一个新的值,而不会改变原有的值。
并发写入
func main() {
var wg sync.WaitGroup
str := "脑子进煎鱼了"
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
str += "!" // 修改 str 变量
fmt.Println(str)
}()
}
wg.Wait()
}
在每个 goroutine 中向 str 变量中添加了一个感叹号。由于多个 goroutine 同时修改了 str 变量,因此可能会出现数据竞争的情况。
会发现程序输出结果会出现乱序或不一致的情况,可以确认 string 类型变量在多个 goroutine 中是不安全的。
string 实现线程安全
使用互斥锁(Mutex)来保护共享变量,确保同一时间只有一个goroutine 可以访问(互斥锁会带来一些性能上的开销)
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var mu sync.Mutex // 定义一个互斥锁
str := "煎鱼"
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock() // 加锁
str += "!"
fmt.Println(str)
mu.Unlock() // 解锁
}()
}
wg.Wait()
}
注意:使用 atomic 包满足不了需求【原子操作通常用于对基本类型(如整数、布尔值、指针等)的原子更改,而不是对字符串的修改】
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var wg sync.WaitGroup
var str atomic.Value // 定义一个原子变量
str.Store("hello, world")
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
oldStr := str.Load().(string) // 读取原子变量的值
newStr := oldStr + "!"
str.Store(newStr) // 写入原子变量的值
fmt.Println(newStr)
}()
}
wg.Wait()
}
这样子也可以保证 string 类型变量的原子操作。但在现实场景下,仍然无法解决多 goroutine 导致的竞态条件(race condition)。
也就是存在多个 goroutine 并发取到的变量值都是一样的,得到的结果还是不固定的,最终还是要用 Mutex 或者 RWMutex 锁来做共享变量保护。
修改字符串
要修改字符串,可先将其转换成 []rune 或 []byte,完成后再转换为 string。⽆论哪种转换,都会重新分配内存,并复制字节数组。
test := "abcd"
runes := []rune(test)
runes[0] = '中'
demo := string(runes)
fmt.Printf("%s\n", demo) // 中bcd
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」