如果想要实现自定义锁,首先要了解go的锁接口定义,然后实现接口里的方法即可(go语言隐式实现接口),go内置的锁的接口定义代码如下:
// A Locker represents an object that can be locked and unlocked.
type Locker interface {
Lock()
Unlock()
}
go的锁一般可以基于go的原子操作cas(atomic.CompareAndSwapUint32)来实现,代码如下:
package goroutine
import (
"runtime"
"sync"
"sync/atomic"
)
type spinLock uint32
const maxBackoff = 16
func (sl *spinLock) Lock() {
backoff := 1
for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
// Leverage the exponential backoff algorithm, see https://en.wikipedia.org/wiki/Exponential_backoff.
for i := 0; i < backoff; i++ {
runtime.Gosched()
}
if backoff < maxBackoff {
backoff <<= 1
}
}
}
func (sl *spinLock) Unlock() {
atomic.StoreUint32((*uint32)(sl), 0)
}
// NewSpinLock instantiates a spin-lock.
func NewSpinLock() sync.Locker {
return new(spinLock)
}
加锁的测试代码如下:
func TestLock(t *testing.T) {
lock := NewSpinLock()
j := 0
wg := sync.WaitGroup{}
for i := 100; i > 0; i-- {
wg.Add(1)
go func() {
defer wg.Done()
lock.Lock()
j++
fmt.Println("j:", j)
lock.Unlock()
}()
}
wg.Wait()
}
加锁后输出结果如下:
=== RUN TestLock
j: 1
j: 2
j: 3
j: 4
j: 5
j: 6
j: 7
j: 8
j: 9
j: 10
j: 11
j: 12
j: 13
j: 14
j: 15
j: 16
j: 17
j: 18
j: 19
j: 20
j: 21
j: 22
j: 23
j: 24
j: 25
j: 26
j: 27
j: 28
j: 29
j: 30
j: 31
j: 32
j: 33
j: 34
j: 35
j: 36
j: 37
j: 38
j: 39
j: 40
j: 41
j: 42
j: 43
j: 44
j: 45
j: 46
j: 47
j: 48
j: 49
j: 50
j: 51
j: 52
j: 53
j: 54
j: 55
j: 56
j: 57
j: 58
j: 59
j: 60
j: 61
j: 62
j: 63
j: 64
j: 65
j: 66
j: 67
j: 68
j: 69
j: 70
j: 71
j: 72
j: 73
j: 74
j: 75
j: 76
j: 77
j: 78
j: 79
j: 80
j: 81
j: 82
j: 83
j: 84
j: 85
j: 86
j: 87
j: 88
j: 89
j: 90
j: 91
j: 92
j: 93
j: 94
j: 95
j: 96
j: 97
j: 98
j: 99
j: 100
--- PASS: TestLock (0.00s)
PASS
未加锁情况下测试代码如下:
func TestLock(t *testing.T) {
//lock := NewSpinLock()
j := 0
wg := sync.WaitGroup{}
for i := 100; i > 0; i-- {
wg.Add(1)
go func() {
defer wg.Done()
//lock.Lock()
j++
fmt.Println("j:", j)
//lock.Unlock()
}()
}
wg.Wait()
}
未加锁情况下输出如下:
=== RUN TestLock
j: 1
j: 3
j: 4
j: 5
j: 6
j: 7
j: 8
j: 9
j: 10
j: 2
j: 11
j: 12
j: 14
j: 15
j: 16
j: 17
j: 18
j: 19
j: 21
j: 22
j: 23
j: 24
j: 25
j: 26
j: 27
j: 28
j: 29
j: 30
j: 31
j: 13
j: 33
j: 34
j: 35
j: 36
j: 37
j: 38
j: 39
j: 40
j: 41
j: 32
j: 44
j: 46
j: 49
j: 51
j: 52
j: 54
j: 57
j: 59
j: 62
j: 50
j: 64
j: 75
j: 47
j: 76
j: 56
j: 55
j: 58
j: 42
j: 78
j: 79
j: 81
j: 84
j: 85
j: 65
j: 66
j: 67
j: 68
j: 69
j: 70
j: 71
j: 72
j: 73
j: 43
j: 53
j: 94
j: 96
j: 61
j: 80
j: 20
j: 82
j: 83
j: 63
j: 45
j: 86
j: 87
j: 88
j: 89
j: 48
j: 90
j: 92
j: 93
j: 93
j: 77
j: 95
j: 97
j: 97
j: 60
j: 91
j: 74
j: 98
--- PASS: TestLock (0.00s)
PASS
通过上述两种情况的对比可以发现go的锁的实现还是很成功的。