golang非阻塞锁的简单实现
发布时间:2020-12-16 19:11:36 所属栏目:大数据 来源:网络整理
导读:对于复杂类型如 container/list ,需要在所有读写操作上使用 sync.mutex 互斥锁以保证数据一致性,互斥锁并发情况下,Lock 操作会阻塞,一直等到其他线程Unlock,但是有的时候因为有一个耗时比较长的操作一直占用锁,我们想让其他线程不在Lock上一直阻塞,而
对于复杂类型如 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~ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |