Administrator
Administrator
发布于 2025-08-12 / 18 阅读
0
0

sync中的Cond、Once、Map

Cond

使协程进入阻塞状态,等待其它线程完成某件事后,使协程继续工作

	var mu sync.Mutex
	cond := sync.NewCond(&mu) //传入的是Locker接口,也就是不限定必须是Mutex,实现了Lock和Unlock就可以
	sharedResource := 0

	go func() {
		mu.Lock()
		for sharedResource == 0 {
			cond.Wait() //符合条件进入等待,并且释放锁
		}
		fmt.Println("得到资源")
		mu.Unlock()
	}()

	go func() {
		time.Sleep(time.Millisecond * 3000) //等待1秒,明确感受到cond.Wait()会在等待期间释放锁的持有,不会因为上面的线程持有锁而导致这个线程无法进入锁(也就是不会导致死锁)
		mu.Lock()
		sharedResource = 1
		fmt.Println("已设置资源")
		cond.Signal() // 唤醒一个等待中的goroutine
		mu.Unlock()
	}()

cond.Broadcast()是释放所有等待中的协程,上面的代码只有一个协程在等待用Signal就可以。

Once

声明的Once实例只会执行一次Do

	var once sync.Once
	once.Do(A)
	once.Do(A) //什么也不会发生
	once.Do(B) //什么也不会发生

func A() {
	fmt.Println("A")
}
func B() {
	fmt.Println("B")
}

OnceFunc

创建一个只能调用一次的(没有返回值的)函数,即使多线程调用也只会调用一次

	var fn = sync.OnceFunc(func() {
		fmt.Println("OnceFunc")
	})
	for i := 0; i < 10; i++ {
		go func() {
			fn()
		}()
	}

OnceValue

允许函数返回一个值,类型不限。fn只能被调一次,多次调用拿到的是首次调用返回的值

	var fn = sync.OnceValue(func() string {
		fmt.Println("OnceValue") //只会被执行一次
		return "test content"
	})
	for i := 0; i < 10; i++ {
		go func() {
			fmt.Println(fn())
		}()
	}

OnceValues

允许二个值

	var fn = sync.OnceValues(func() (string, int) {
		fmt.Println("OnceValues")
		return "test content", 666
	})
	for i := 0; i < 10; i++ {
		go func() {
			fmt.Println(fn())
		}()
	}

Map

线程安全的键值对

基本

	var m sync.Map
	m.Store("aa", "111")
	fmt.Println(m.Load("aa"))             //"111", true
	m.Range(func(k, v interface{}) bool { //遍历所有键值
		fmt.Println(k, v)
		return true //返回false中断遍历
	})
	m.Delete("aa")
	m.Clear()

Swap

	var m sync.Map
	m.Store("aa", "111")
	fmt.Println(m.Swap("aa", "333")) //"111", true,替换键的值并返因之前的值
	fmt.Println(m.Load("aa"))        //"333", true

	fmt.Println(m.Swap("bb", 666)) // <nil>, false,在此之前健不存在
	fmt.Println(m.Load("bb"))      //"666", true

LoadAndDelete - 取值后删除键

	var m sync.Map
	m.Store("aa", "111")
	val, loaded := m.LoadAndDelete("aa") //获取值然后移除对应的键
	fmt.Println(val, loaded)             // "111", true
	val, loaded = m.Load("aa")
	fmt.Println(val, loaded) // <nil>, false

LoadOrStore - 取或设

	var m sync.Map
	m.Store("aa", "111")
	fmt.Println(m.LoadOrStore("aa", "222")) //"111", true,如果存在则取出,不存在则将值设置到键
	fmt.Println(m.LoadOrStore("bb", "222")) // "222", false,将bb设为222

CompareAndDelete

当前值是xxx则删除,不是则什么也不做

	var m sync.Map
	m.Store("aa", "111")
	fmt.Println(m.CompareAndDelete("aa", "222")) //false
	fmt.Println(m.CompareAndDelete("aa", "111")) //true

CompareAndSwap

	var m sync.Map
	m.Store("aa", "111")
	fmt.Println(m.CompareAndSwap("aa", "222", "333")) //false, 当前值为222则更换为333
	fmt.Println(m.CompareAndSwap("aa", "111", "444")) //true, 当前值为111则更换为444


评论