Go语言中的线程同步-锁机制

互斥锁

若不加互斥锁,下面这段程序中map[1]的数值可能为负数(多次执行结果可能不相同,但大多都为负数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var lock sync.Mutex

func consumer(m map[int]int) {
// 定义一个消费者,用来消费传入的map中的数值,直到数值小于或等于0
// 在没有使用互斥锁时,map中的数值可能会出现负数
// 读写锁适合在读写频率相差不多的情况下使用,其会影响性能
for i := 0; i < 100; i++ {
go func(m1 map[int]int) {
lock.Lock() //上锁
if m1[1] > 0 {
time.Sleep(time.Microsecond)
m1[1] = m1[1] - 1
}
lock.Unlock() //解锁
}(m)
}
}

func test1() {
m := make(map[int]int, 1)
m[1] = 10
consumer(m)
time.Sleep(3 * time.Second)
fmt.Printf("map:%v", m)
}

func main() {
test1()
}
---------------------
map:map[1:0]

读写锁

下面这段程序可以看出:在读锁时,两个读操作可以并发执行, 而在写锁时,只有一个写锁释放了,另一个写锁才会执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
var rwlock sync.RWMutex

func read(i int) {
fmt.Println(i, "read start")
rwlock.RLock()
start := 0
pr := "read"

for {
if start > 10 {
break
}
time.Sleep(time.Millisecond)
pr += "."
fmt.Println(i, pr)
start++
}
rwlock.RUnlock()
fmt.Println(i, "read end")
}

func write(i int) {
fmt.Println(i, "write start")
rwlock.Lock()
start := 0
pr := "write"

for {
if start > 10 {
break
}
time.Sleep(time.Millisecond)
pr += "."
fmt.Println(i, pr)
start++
}
rwlock.Unlock()
fmt.Println(i, "write end")
}

func test2() {
// 读写锁,适合用在读多写少的情况下
// 进行读操作的时候无需等待读锁的结束
go read(1)
go write(1)
go read(2)
go write(2)
time.Sleep(time.Second * 5)

}

func main() {
test2()
}
--------------------------
1 read start
2 read start
1 write start
2 write start
1 read.
2 read.
1 read..
2 read..
1 read...
1 read....
2 read...
2 read....
1 read.....
2 read.....
1 read......
1 read.......
2 read......
1 read........
2 read.......
1 read.........
2 read........
2 read.........
1 read..........
2 read..........
1 read...........
1 read end
2 read...........
2 read end
1 write.
1 write..
1 write...
1 write....
1 write.....
1 write......
1 write.......
1 write........
1 write.........
1 write..........
1 write...........
1 write end
2 write.
2 write..
2 write...
2 write....
2 write.....
2 write......
2 write.......
2 write........
2 write.........
2 write..........
2 write...........
2 write end