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

posted @ 2021-10-13 16:15  惊风破浪的博客  阅读(384)  评论(1编辑  收藏  举报