面试题答案
一键面试在Go语言中,以下是一些会用到原子操作的并发场景:
计数器
当多个goroutine需要对一个计数器进行增减操作时,如果不使用原子操作,可能会出现竞态条件。
示例代码:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64
var wg sync.WaitGroup
numGoroutines := 1000
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&counter, 1)
}()
}
wg.Wait()
fmt.Println("Final counter value:", counter)
}
解释:在上述代码中,多个goroutine同时对counter
进行增加操作。使用atomic.AddInt64
函数,它以原子方式将给定值加到counter
上,保证每次操作都是完整且不可分割的,从而避免了竞态条件,确保并发安全。
标志位的设置与检查
例如在多个goroutine中需要设置或检查一个标志位,以表明某个操作是否完成。
示例代码:
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var flag int32
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
time.Sleep(2 * time.Second)
atomic.StoreInt32(&flag, 1)
}()
go func() {
defer wg.Done()
for {
if atomic.LoadInt32(&flag) == 1 {
fmt.Println("Flag is set.")
break
}
time.Sleep(500 * time.Millisecond)
}
}()
wg.Wait()
}
解释:第一个goroutine在2秒后设置标志位flag
,第二个goroutine不断检查flag
。atomic.StoreInt32
和atomic.LoadInt32
函数分别用于原子地设置和加载flag
的值,确保在并发环境下,设置和检查操作的正确性,避免竞态。