0%

Go语言锁

线程池的基本思想是对象池,在程序启动时就开辟一块内存空间,里面存放了众多(未死亡的)的线程,池中的线程执行调度由池管理器来处理,当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象带来的性能开销,节省了系统的资源。

一、基础

  1. 竞态条件

  2. 互斥锁sync.Mutex,开箱即用,是一种绝对锁,同一时间只能有一个锁,用来保证多个goroutine并发地访问同一个共享资源时的完全串行。

    • 不要重复锁定互斥锁
    • 不要忘记解锁互斥锁,必要时使用defer语句
    • 不要对尚未锁定或者已解锁的互斥锁解锁
    • 不要在多个函数之间直接传递互斥锁
  3. 读写锁sync.RWMutex,开箱即用,是互斥锁的一种扩展,它有两种锁:写锁和读锁:

    • 在写锁已被锁定的情况下再试图锁定写锁,会阻塞当前的goroutine
    • 在写锁已被锁定的情况下试图锁定读锁,也会阻塞当前的goroutine
    • 在读锁已被锁定的情况下试图锁定写锁,同样会阻塞当前的goroutine
    • 在读锁已被锁定的情况下再试图锁定读锁,并不会阻塞当前的goroutine
  4. 死锁

二、使用

  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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package main

import (
"fmt"
"sync"
)

func main() {
counter := 0
var wg sync.WaitGroup
wg.Add(100)
for j := 0; j < 100 ; j++{
go func() {
counter += 1
wg.Done()
}()
}
wg.Wait()
fmt.Println(counter)

var wg1 sync.WaitGroup
var mt1 sync.Mutex
var counter1 int
wg1.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
mt1.Lock()
counter1++
mt1.Unlock()
wg1.Done()
}(i)
}
wg1.Wait()
fmt.Println(counter1)

var wg2 sync.WaitGroup
var mt2 sync.RWMutex
var counter2 int
wg2.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
mt2.RLock()
counter2++
mt2.RUnlock()
wg2.Done()
}(i)
}
wg2.Wait()
fmt.Println(counter2)
}

三、参考

  1. 参考一