golang非阻塞锁的简单实现

吾爱 · · 3995 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

对于复杂类型如 container/list ,需要在所有读写操作上使用 sync.mutex 互斥锁以保证数据一致性,互斥锁并发情况下,Lock 操作会阻塞,一直等到其他线程Unlock,但是有的时候因为有一个耗时比较长的操作一直占用锁,我们想让其他线程不在Lock上一直阻塞,而是直接走其他业务流程。

举一个很简单的场景:在多人并发抽奖环节,为了保证不出现负库存,我们可以通过竞争锁,第一个获取锁的人可能中奖,而其他并发过来的请求获取锁失败(而不是一直阻塞在Lock()),直接当做未中奖处理。

思考了一下,有一个思路,我们可以用两道锁,第一道锁用来判断锁状态,第二道锁才是真正的耗时任务用的锁。

直接上代码

type NBLocker struct{
	l1 sync.Mutex
	l2 sync.Mutex
	locked bool
}

func (NBLocker *NBLocker) Lock() (success bool) {
	NBLocker.l1.Lock()
	defer NBLocker.l1.Unlock()
	if NBLocker.locked == false {
		NBLocker.locked = true
		success = true
		NBLocker.l2.Lock()
	}
	return
}

func (NBLocker *NBLocker) Unlock() {
	NBLocker.l1.Lock()
	defer NBLocker.l1.Unlock()
	NBLocker.locked = false
	NBLocker.l2.Unlock()
}

使用

type foo struct {
	mux NBLocker
}

func (self *foo) Bong(wg *sync.WaitGroup) {
	defer wg.Done()
	if !self.mux.Lock() {
		fmt.Println("获取锁失败")
		return
	}
	defer self.mux.Unlock()
	time.Sleep(time.Second) //停顿一秒
	fmt.Println("bong~")
}

func main() {
	f := &foo{}
	wg := &sync.WaitGroup{}
	wg.Add(4)
	go f.Bong(wg)
	go f.Bong(wg)
	go f.Bong(wg)
	time.Sleep(time.Second *2)
	go f.Bong(wg)
	wg.Wait()
}

如果获取第二道锁失败,NBLocker.Lock() 方法会直接返回false,这时候只需要判断一下就可以直接跳过"抽奖环节"

以上例程输出

获取锁失败
获取锁失败
bong~
bong~

 


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:吾爱

查看原文:golang非阻塞锁的简单实现

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3995 次点击  
加入收藏 微博
2 回复  |  直到 1999-12-31 16:00:00
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传