go的互斥锁,读写互斥锁,简单redis分布式锁
互斥锁
- 保证读取每个变量都是安全的,互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待锁;
package main
import (
"fmt"
"sync"
)
var x int64
var wg sync.WaitGroup
var lock sync.Mutex
func add() {
for i := 0; i < 5000; i++ {
lock.Lock() //加锁
x = x + 1
lock.Unlock() //解锁
}
wg.Done()
}
func main() {
wg.Add(2)
go add()
go add()
wg.Wait()
fmt.Println(x)
}
互斥锁
package main
import (
"fmt"
"strconv"
"sync"
"time"
)
//读写锁分为两种:读锁和写锁。
//当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;
//当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。
func main() {
var rwLock sync.RWMutex
// 获取写锁
//for i := 0; i < 5; i++ {
// go func(i int) {
// rwLock.Lock()
// defer rwLock.Unlock()
// fmt.Println("write func " + strconv.Itoa(i) + " get wlock at " + time.Now().String())
// time.Sleep(time.Second)
// }(i)
//}
// 获取读锁
for i := 0 ; i < 5 ;i ++{
go func(i int) {
rwLock.RLock()
defer rwLock.RUnlock()
fmt.Println("read func " + strconv.Itoa(i) +" get rlock at " + time.Now().String())
time.Sleep(time.Second)
}(i)
}
// 保证所有的 goroutine 执行结束
time.Sleep(time.Second * 10)
}
redis分布式锁
- 1.通过setnx命令设置key,不存在设置它的值,否则什么也不做
- 2.客户端1申请加锁,加锁成功,客户端1加锁设置一般是自已的线程id,或者uuid,客户端1设置的锁客户端2不能打开,客户端 2 申请加锁,因为后到达,加锁失败
- 3.申请锁时,给这把锁设置一个「租期」不然会造成死锁
- 4.也可以通过Lua脚本实现解锁
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/bsm/redislock"
"github.com/go-redis/redis/v8"
)
func main() {
//连接redis
client := redis.NewClient(&redis.Options{
Network: "tcp",
Addr: "127.0.0.1:6379",
})
defer client.Close()
//上下文
ctx := context.Background()
//创建一个锁客户端
locker := redislock.New(client)
// 尝试获取锁
lock, err := locker.Obtain(ctx, "my-key", 100*time.Millisecond, nil)
if err == redislock.ErrNotObtained {
fmt.Println("无法获取到锁!")
} else if err != nil {
log.Fatalln(err)
}
// 延迟
defer lock.Release(ctx)
fmt.Println("我有一个锁!")
// 睡眠并检查剩余的TTL。
time.Sleep(50 * time.Millisecond)
if ttl, err := lock.TTL(ctx); err != nil {
log.Fatalln(err)
} else if ttl > 0 {
fmt.Println("是的,我的锁还在呀!!")
}
//打开锁
if err := lock.Refresh(ctx, 100*time.Millisecond, nil); err != nil {
log.Fatalln(err)
}
// 检测锁
time.Sleep(100 * time.Millisecond)
if ttl, err := lock.TTL(ctx); err != nil {
log.Fatalln(err)
} else if ttl == 0 {
fmt.Println("现在,我的锁过期了\n!")
}
}
参考 https://github.com/bsm/redislock
https://www.cnblogs.com/bushuwei/p/15161668.html