利用通道的阻塞特性,可以创建一个缓冲大小为1的通道,只有第一个往通道里放数据的协程会成功,其它的只能阻塞等待,这个过程相当于加锁,获得锁的协程任务执行完毕后往通道中取出数据就是解锁,然后其他的协程就可以继续获得锁了,实现代码如下:
package main
import (
"fmt"
"time"
)
type Lock struct {
ch chan struct{}
}
func NewLock() *Lock {
l:=&Lock{}
l.ch = make(chan struct{},1)
return l
}
//获取锁,未获取到一直阻塞
func (l *Lock) Lock() {
l.ch <- struct{}{}
}
//尝试获取锁,无论是否获取到锁,立即返回
func (l *Lock) TryLock() bool {
select {
case l.ch <- struct{}{}:
return true
default:
return false
}
}
//尝试获取锁,在规定时间内仍未获得锁则返回
func (l *Lock) TryLockWithTimeout(t time.Duration) bool {
timer:=time.NewTimer(t)
select {
case l.ch <- struct{}{}:
timer.Stop()
return true
case <-timer.C:
return false
}
}
//解锁
func (l *Lock) Unlock() {
select {
case <- l.ch:
return
default:
}
}
var l *Lock
func main() {
l = NewLock()
go task(1)
go task(2)
go task(3)
time.Sleep(8*time.Second)
}
func task(i int) {
l.Lock()
defer l.Unlock()
fmt.Println("任务",i,"开始执行")
time.Sleep(2*time.Second)
fmt.Println("任务",i,"执行完毕")
}
执行结果:
任务 1 开始执行
任务 1 执行完毕
任务 2 开始执行
任务 2 执行完毕
任务 3 开始执行
任务 3 执行完毕