------------------------------------------------------------ 临时对象池 Pool 用于存储临时对象,它将使用完毕的对象存入对象池中,在须要的时候取出来重复使用,目的是为了不重复建立相同的对象形成 GC 负担太重。其中存放的临时对象随时可能被 GC 回收掉(若是该对象再也不被其它变量引用)。 从 Pool 中取出对象时,若是 Pool 中没有对象,将返回 nil,可是若是给 Pool.New 字段指定了一个函数的话,Pool 将使用该函数建立一个新对象返回。 Pool 能够安全的在多个例程中并行使用,但 Pool 并不适用于全部空闲对象,Pool 应该用来管理并发的例程共享的临时对象,而不该该管理短寿命对象中的临时对象,由于这种状况下内存不能很好的分配,这些短寿命对象应该本身实现空闲列表。 Pool 在开始使用以后,不能再被复制。 ------------------------------ type Pool struct { // 建立临时对象的函数 New func() interface{} } // 向临时对象池中存入对象 func (p *Pool) Put(x interface{}) // 从临时对象池中取出对象 func (p *Pool) Get() interface{} ------------------------------------------------------------ 单次执行 Once 的做用是屡次调用但只执行一次,Once 只有一个方法,Once.Do(),向 Do 传入一个函数,这个函数在第一次执行 Once.Do() 的时候会被调用,之后再执行 Once.Do() 将没有任何动做,即便传入了其它的函数,也不会被执行,若是要执行其它函数,须要从新建立一个 Once 对象。 Once 能够安全的在多个例程中并行使用。 ------------------------------ // 屡次调用仅执行一次指定的函数 f func (o *Once) Do(f func()) ------------------------------ // 示例:Once func main() { var once sync.Once onceBody := func() { fmt.Println("Only once") } done := make(chan bool) for i := 0; i < 10; i++ { go func() { once.Do(onceBody) // 屡次调用只执行一次 done <- true }() } for i := 0; i < 10; i++ { <-done } } // 输出结果: // Only once ------------------------------------------------------------ 互斥锁 互斥锁用来保证在任一时刻,只能有一个例程访问某对象。Mutex 的初始值为解锁状态。Mutex 一般做为其它结构体的匿名字段使用,使该结构体具备 Lock 和 Unlock 方法。 Mutex 能够安全的在多个例程中并行使用。 ------------------------------ // Locker 接口包装了基本的 Lock 和 UnLock 方法,用于加锁和解锁。 type Locker interface { Lock() Unlock() } // Lock 用于锁住 m,若是 m 已经被加锁,则 Lock 将被阻塞,直到 m 被解锁。 func (m *Mutex) Lock() // Unlock 用于解锁 m,若是 m 未加锁,则该操做会引起 panic。 func (m *Mutex) Unlock() ------------------------------ // 示例:互斥锁 type SafeInt struct { sync.Mutex Num int } func main() { count := SafeInt{} done := make(chan bool) for i := 0; i < 10; i++ { go func(i int) { count.Lock() // 加锁,防止其它例程修改 count count.Num += i fmt.Print(count.Num, " ") count.Unlock() // 修改完毕,解锁 done <- true }(i) } for i := 0; i < 10; i++ { <-done } } // 输出结果(不固定): // 2 11 14 18 23 29 36 44 45 45 ------------------------------------------------------------ 读写互斥锁 RWMutex 比 Mutex 多了一个“读锁定”和“读解锁”,可让多个例程同时读取某对象。RWMutex 的初始值为解锁状态。RWMutex 一般做为其它结构体的匿名字段使用。 Mutex 能够安全的在多个例程中并行使用。 ------------------------------ // Lock 将 rw 设置为写锁定状态,禁止其余例程读取或写入。 func (rw *RWMutex) Lock() // Unlock 解除 rw 的写锁定状态,若是 rw 未被写锁定,则该操做会引起 panic。 func (rw *RWMutex) Unlock() // RLock 将 rw 设置为读锁定状态,禁止其余例程写入,但能够读取。 func (rw *RWMutex) RLock() // Runlock 解除 rw 的读锁定状态,若是 rw 未被读锁顶,则该操做会引起 panic。 func (rw *RWMutex) RUnlock() // RLocker 返回一个互斥锁,将 rw.RLock 和 rw.RUnlock 封装成了一个 Locker 接口。 func (rw *RWMutex) RLocker() Locker ------------------------------------------------------------ 组等待 WaitGroup 用于等待一组例程的结束。主例程在建立每一个子例程的时候先调用 Add 增长等待计数,每一个子例程在结束时调用 Done 减小例程计数。以后,主例程经过 Wait 方法开始等待,直到计数器归零才继续执行。 ------------------------------ // 计数器增长 delta,delta 能够是负数。 func (wg *WaitGroup) Add(delta int) // 计数器减小 1 func (wg *WaitGroup) Done() // 等待直到计数器归零。若是计数器小于 0,则该操做会引起 panic。 func (wg *WaitGroup) Wait() ------------------------------ // 示例:组等待 func main() { wg := sync.WaitGroup{} wg.Add(10) for i := 0; i < 10; i++ { go func(i int) { defer wg.Done() fmt.Print(i, " ") }(i) } wg.Wait() } // 输出结果(不固定): // 9 3 4 5 6 7 8 0 1 2 ------------------------------------------------------------ 条件等待 条件等待经过 Wait 让例程等待,经过 Signal 让一个等待的例程继续,经过 Broadcast 让全部等待的例程继续。 在 Wait 以前应当手动为 c.L 上锁,Wait 结束后手动解锁。为避免虚假唤醒,须要将 Wait 放到一个条件判断循环中。官方要求的写法以下: c.L.Lock() for !condition() { c.Wait() } // 执行条件知足以后的动做... c.L.Unlock() Cond 在开始使用以后,不能再被复制。 ------------------------------ type Cond struct { L Locker // 在“检查条件”或“更改条件”时 L 应该锁定。 } // 建立一个条件等待 func NewCond(l Locker) *Cond // Broadcast 唤醒全部等待的 Wait,建议在“更改条件”时锁定 c.L,更改完毕再解锁。 func (c *Cond) Broadcast() // Signal 唤醒一个等待的 Wait,建议在“更改条件”时锁定 c.L,更改完毕再解锁。 func (c *Cond) Signal() // Wait 会解锁 c.L 并进入等待状态,在被唤醒时,会从新锁定 c.L func (c *Cond) Wait() ------------------------------ // 示例:条件等待 func main() { condition := false // 条件不知足 var mu sync.Mutex cond := sync.NewCond(&mu) // 让例程去创造条件 go func() { mu.Lock() condition = true // 更改条件 cond.Signal() // 发送通知:条件已经知足 mu.Unlock() }() mu.Lock() // 检查条件是否知足,避免虚假通知,同时避免 Signal 提早于 Wait 执行。 for !condition { // 等待条件知足的通知,若是收到虚假通知,则循环继续等待。 cond.Wait() // 等待时 mu 处于解锁状态,唤醒时从新锁定。 } fmt.Println("条件知足,开始后续动做...") mu.Unlock() } // 输出结果: // 条件知足,开始后续动做... ------------------------------------------------------------