线程安全是什么
线程安全是指在多线程环境下,程序的执行能够正确地处理多个线程并发访问共享数据的情况,保证程序的正确性和可靠性。
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 可以访问(互斥锁会带来一些性能上的开销)
【原子操作通常用于对基本类型(如整数、布尔值、指针等)的原子更改,而不是对字符串的修改】