面试题答案
一键面试原子操作确保多线程环境下数据一致性的原理
在Go语言中,原子操作是由底层硬件和操作系统支持的不可分割的操作。在多线程环境下,多个线程可能同时访问和修改共享数据,这会导致数据竞争和不一致问题。原子操作通过保证操作的原子性,即操作在执行过程中不会被其他线程中断,从而确保数据一致性。
atomic
包中常用的原子操作函数及其适用场景
atomic.AddInt64
- 函数签名:
func AddInt64(addr *int64, delta int64) (new int64)
- 适用场景:用于在多线程环境下安全地对
int64
类型的共享变量进行加法操作。例如,在实现计数器时,如果多个线程可能同时对计数器进行增加操作,使用atomic.AddInt64
可以避免数据竞争。 - 示例代码:
- 函数签名:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&counter, 1)
}()
}
wg.Wait()
fmt.Println("Final counter value:", atomic.LoadInt64(&counter))
}
atomic.CompareAndSwapInt64
- 函数签名:
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
- 适用场景:用于实现乐观锁。只有当共享变量
addr
的值等于old
时,才将其值更新为new
,并返回true
,否则返回false
。常用于多线程环境下需要根据某个条件更新共享变量的场景。 - 示例代码:
- 函数签名:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var value int64 = 10
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
success := atomic.CompareAndSwapInt64(&value, 10, 20)
if success {
fmt.Println("Value successfully updated")
} else {
fmt.Println("Value was not updated")
}
}()
}
wg.Wait()
}
atomic.LoadInt64
- 函数签名:
func LoadInt64(addr *int64) (val int64)
- 适用场景:用于在多线程环境下安全地读取
int64
类型的共享变量。确保读取操作不会受到其他线程写操作的干扰。 - 示例代码:
- 函数签名:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var data int64 = 42
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
defer wg.Done()
value := atomic.LoadInt64(&data)
fmt.Println("Read value:", value)
}()
}
wg.Wait()
}
atomic.StoreInt64
- 函数签名:
func StoreInt64(addr *int64, val int64)
- 适用场景:用于在多线程环境下安全地存储
int64
类型的值到共享变量。确保存储操作不会被其他线程干扰。 - 示例代码:
- 函数签名:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var data int64
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.StoreInt64(&data, int64(i*10))
}()
}
wg.Wait()
fmt.Println("Final stored value:", atomic.LoadInt64(&data))
}