package main
import (
"log"
"math/rand"
"sync"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
const N = 5
var values [N]int32
var wg sync.WaitGroup
wg.Add(N)
for i := 0; i < N; i++ {
i := i
go func() {
values[i] = 50 + rand.Int31n(50)
log.Println("Done:", i)
wg.Done() // <=> wg.Add(-1)
}()
}
wg.Wait()
// All elements are guaranteed to be
// initialized now.
log.Println("values:", values)
}
package main
import (
"log"
"sync"
)
func main() {
log.SetFlags(0)
x := 0
doSomething := func() {
x++
log.Println("Hello")
}
var wg sync.WaitGroup
var once sync.Once
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
once.Do(doSomething)
log.Println("world!")
}()
}
wg.Wait()
log.Println("x =", x) // x = 1
}
Both of the *sync.Mutex
and *sync.RWMutex
types implement the sync.Locker
interface. So they both have two methods, Lock
and Unlock
, to prevent multiple data users from using a piece of data concurrently.
A Mutex
value is often called a mutual exclusion lock. A zero Mutex
value is an unlocked mutex. A Mutex
value can only be locked when it is in unlocked status. In other words, once an addressable Mutex
value m
is locked successfully (a.k.a., a m.Lock()
method call returns), a new attempt by a goroutine to lock the Mutex
value will make the goroutine enter blocking state, until the Mutex
value is unlocked (through a later m.Unlock()
call).
Please note that m.Lock()
and m.Unlock()
are shorthands of (&m).Lock()
and (&m).Unlock()
, respectively.
package main
import (
"fmt"
"runtime"
"sync"
)
type Counter struct {
m sync.Mutex
n uint64
}
func (c *Counter) Value() uint64 {
c.m.Lock()
defer c.m.Unlock()
return c.n
}
func (c *Counter) Increase(delta uint64) {
c.m.Lock()
c.n += delta
c.m.Unlock()
}
func main() {
var c Counter
for i := 0; i < 100; i++ {
go func() {
for k := 0; k < 100; k++ {
c.Increase(1)
}
}()
}
// The loop is just for demo purpose.
for c.Value() < 10000 {
runtime.Gosched()
}
fmt.Println(c.Value()) // 10000
}
RWMutex
的存在主要是对读优化,我们这样定义:
- 写锁定(
lock
),对读写操作进行锁定 - 写解锁(
Unlock
),对写锁定进行解锁 - 读锁定(
RLock
),对读操作进行锁定 - 读解锁(
RUnlock
),对读锁定进行解锁
对于一个RWMutex
值m
,遵循规则:
- 同时只有一个 goroutine 能够获得写锁定,当一个 goroutine 获得写锁定之后,其他无论是读锁定还是写锁定都将阻塞直到写锁定解锁
- 同时可以有任意多个 goroutine 获得读锁定,当一个 goroutine 获得读锁定之后,其他 goroutine 也能获得读锁定,但是写锁定将等待所有读锁定解锁之后才能够获取写锁定
- 不能同时获得写锁定和读锁定(读和写互斥)
- 假设
m
的读锁定已经被获取,在队列中已经有写锁定被阻塞,如果这时候有其他 goroutine 需要读锁定,为了避免循环读锁定,这个 goroutine 将被阻塞,m
的读锁定被释放后,队列中那个需要写锁定的 goroutine 将被执行 - 假设
m
的写锁定已经被获取,在队列中已经有读锁定被阻塞,如果这时候有其他 goroutine 需要写锁定,为了避免循环写锁定,这个 goroutine 将被阻塞,m
的写锁定被释放后,队列中那个需要读锁定的 goroutine 将被执行
package main
import (
"fmt"
"runtime"
"sync"
)
type Counter struct {
m nc.RWMutex
n uint64
}
func (c *Counter) Value() uint64 {
c.m.RLock()
defer c.m.RUnlock()
return c.n
}
func (c *Counter) Increase(delta uint64) {
c.m.Lock()
c.n += delta
c.m.Unlock()
}
func main() {
var c Counter
for i := 0; i < 100; i++ {
go func() {
for k := 0; k < 100; k++ {
c.Increase(1)
}
}()
}
// The loop is just for demo purpose.
for c.Value() < 10000 {
runtime.Gosched()
}
fmt.Println(c.Value()) // 10000
}
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
//Store
m.Store("name", "Joe")
m.Store("gender", "Male")
//LoadOrStore
//若key不存在,则存入key和value,返回false和输入的value
v, ok := m.LoadOrStore("name1", "Jim")
fmt.Println(ok, v) //false Jim
//若key已存在,则返回true和key对应的value,不会修改原来的value
v, ok = m.LoadOrStore("name", "aaa")
fmt.Println(ok, v) //true Joe
//Load
v, ok = m.Load("name")
if ok {
fmt.Println("key存在,值是: ", v)
} else {
fmt.Println("key不存在")
}
//Range
//遍历sync.Map
f := func(k, v interface{}) bool {
fmt.Println(k, v)
return true
}
m.Range(f)
//Delete
m.Delete("name1")
fmt.Println(m.Load("name1"))
}