分布式锁的实现
package main
import (
"context"
"errors"
"github.com/bsm/redislock"
"github.com/go-redis/redis/v8"
"log"
"math/rand"
"time"
)
var (
WaitLockTimeout = errors.New("wait for lock timeout")
)
type WatchDogLock struct {
WaitLockTime time.Duration
KeyTTL time.Duration
LockKey string
realLock *redislock.Lock
client *redis.Client
cancelWatchDog func()
}
func NewWatchDogLock(waitLockTime time.Duration, keyTTL time.Duration, lockKey string, cli *redis.Client) *WatchDogLock {
return &WatchDogLock{
WaitLockTime: waitLockTime,
KeyTTL: keyTTL,
LockKey: lockKey,
client: cli,
}
}
func (w *WatchDogLock) _close() error {
if w.client != nil {
defer w.client.Close()
}
if w.cancelWatchDog != nil {
w.cancelWatchDog()
}
if w.realLock != nil {
err := w.realLock.Release(context.Background())
return err
}
return nil
}
func (w *WatchDogLock) TryLock() (ok bool, err error) {
locker := redislock.New(w.client)
var LockWaitTimeout = time.After(w.WaitLockTime)
var lock *redislock.Lock
rand.Seed(time.Now().Unix())
tryLock:
for {
select {
case <-LockWaitTimeout:
log.Println("获取锁失败,已到超时时间")
return false, WaitLockTimeout
default:
lock, err = locker.Obtain(context.Background(), w.LockKey, w.KeyTTL, nil)
if err == redislock.ErrNotObtained {
var v = rand.Int63n(100)
log.Println("rand v " ,v)
time.Sleep(time.Duration(int64(time.Millisecond) * (500 + v)))
log.Println(" try ...")
continue tryLock
} else if err != nil {
log.Println("lock unknown status %+v", err)
return false, nil
}
break tryLock
}
}
if lock == nil {
log.Println("未知异常,获取锁失败 lock==nil")
return false, errors.New("无法获得锁")
}
w.realLock = lock
var ctx, cancel = context.WithCancel(context.Background())
w.cancelWatchDog = cancel
var watchDog = func() {
for {
select {
case <-ctx.Done():
log.Println("cancel watchdog")
return
default:
lock.Refresh(ctx, time.Second*30, nil)
select {
case <-ctx.Done():
log.Println("cancel watchdog 109")
return
case <-time.After(time.Second * 10):
}
}
}
}
go watchDog()
return true, nil
}
func (w *WatchDogLock) UnLock() error {
return w._close()
}
package main
import (
"github.com/go-redis/redis/v8"
"log"
"time"
)
func worker(id int) {
var client = redis.NewClient(&redis.Options{
Network: "tcp",
Addr: "127.0.0.1:6379",
})
defer client.Close()
locker := NewWatchDogLock(time.Second*8, time.Second*50, "mylock0", client)
ok, err := locker.TryLock()
if err != nil {
if err == WaitLockTimeout {
log.Println("等待锁超时了")
}
log.Println(err)
return
}
if ok {
log.Println("=== 获取锁成功 ====",id)
time.Sleep(time.Second*2)
err = locker.UnLock()
log.Println("err info",err)
}else {
panic("获得锁失败")
}
}
func main() {
for i := 0; i < 2; i++ {
go worker(i)
}
time.Sleep(time.Second*40)
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构