Go中sync包学习


前面刚讲到goroutine和channel,通过goroutine启动一个协程,通过channel的方式在多个goroutine中传递消息来保证并发安全。今天我们来学习sync包,这个包是Go提供的基础包,提供了锁的支持。但是Go官方给的建议是:不要以共享内存的方式来通信,而是要以通信的手段来共享内存。所以他们是提倡使用channel的方式来实现并发控制。

学过Java的同学对锁的概念肯定不陌生,在Java中提供Sychronized关键字提供独占锁,Lock类提供读写锁。在sync包中实现的功能也是与锁相关,包中主要包含的对象有:

  • Locker:提供了加锁和解锁的接口
  • Cond:条件等待通过 Wait 让例程等待,通过 Signal 让一个等待的例程继续,通过 Broadcast 让所有等待的例程继续。
  • Map:线程安全的map ,同时被多个goroutines调用是安全的。
  • Mutex:互斥锁,用来保证在任一时刻,只能有一个例程访问某对象。实现了Locker接口。Mutex 的初始值为解锁状态,Mutex 通常作为其它结构体的匿名字段使用,使该结构体具有 Lock 和 Unlock 方法
  • Once:Once 是一个可以被多次调用但是只执行一次,若每次调用Do时传入参数f不同,但是只有第一个才会被执行。
  • Pool:用于存储临时对象,它将使用完毕的对象存入对象池中,在需要的时候取出来重复使用,其中存放的临时对象随时可能被 GC 回收掉如果该对象不再被其它变量引用
  • RWMutex:读写互斥锁,RWMutex 比 Mutex 多了一个“读锁定”和“读解锁”,可以让多个例程同时读取某对象。RWMutex 的初始值为解锁状态。RWMutex 通常作为其它结构体的匿名字段使用。
  • WaitGroup :用于等待一组例程的结束。主例程在创建每个子例程的时候先调用 Add 增加等待计数,每个子例程在结束时调用 Done 减少例程计数。之后主例程通过 Wait 方法开始等待,直到计数器归零才继续执行。

Once.Do(),向 Do 传入一个函数,这个函数在第一次执行 Once.Do() 的时候会被调用,以后再执行 Once.Do() 将没有任何动作,即使传入了其它的函数,也不会被执行,如果要执行其它函数,需要重新创建一个 Once 对象。

看一个很简单的例子:

package main

import (
	"fmt"
	"sync"
)


func main() {
	var once sync.Once
	onceBody := func() {
		fmt.Println("我只会出现一次")
	}
	done := make(chan bool)
	for i := 0; i < 3; i++ {
		go func() {
			once.Do(onceBody)
			done <- true
		}()
	}
	for i := 0; i < 3; i++ {
		<-done
	}
}

相关