文档章节

golang非阻塞锁的简单实现

吾爱
 吾爱
发布于 2017/04/04 12:19
字数 408
阅读 273
收藏 1
Go

对于复杂类型如 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~

 

© 著作权归作者所有

上一篇: 学习笔记
吾爱
粉丝 142
博文 271
码字总数 91680
作品 0
后端工程师
私信 提问
基于 PHP 协程的网络服务框架--Zan PHP Framework

Zan PHP Framework 是有赞开源的基于 PHP 协程的网络服务框架,提供最简单的方式开发面向 C10K+ 的高并发SOA服务和RPC服务。 该项目每天为2,000+个服务提供300,000,000+次访问量支持,广泛应...

匿名
2017/06/21
2.1K
6
Golang基于redis实现的分布式信号量(semaphore)

前言: Semaphore是信号量,作用? 我想大家都知道。semaphore跟mutex的区别我想大家也知道了,我这里就不老生常谈,重复讲解了,有兴趣的朋友可以自行google相关的同步锁文章。 该文章后续会有...

rfyiamcool
2017/10/17
0
0
Zan-Group/zanphp

基于 PHP 协程的网络服务框架,提供最简单的方式开发面向 C10K+ 的高并发SOA服务和RPC服务。 每天为2,000+个服务提供300,000,000+次访问量支持,广泛应用于有赞各项业务。 核心特性 基于 实现...

Zan-Group
2017/06/21
0
0
PHP网络服务框架--zan

Zan PHP Framework Zan PHP是基于PHP协程的网络服务框架,提供最简单的方式开发面向C10K+的高并发HTTP服务或SOA服务。 核心特效 基于 yield 实现了独立堆栈的协程 类似于 Golang 的并发编程模...

demon666
2016/07/21
1K
0
cgo阻塞调用引起golang线程暴增

前言: 我们知道golang抽象了一个pmg的体系概念,里面p可以理解为协程管理队列,在多核主机下go默认会设置跟cpu core相匹配的队列数。 该文章后续仍在不断的更新修改中, 请移步到原文地址 ht...

rfyiamcool
2018/08/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Oracle SQL语法实例合集

如需转载请注明出处https://my.oschina.net/feistel/blog/3052024 目的:迅速激活Oracle SQL 参考:《Oracle从入门到精通》 ------------------------------------------------------------......

LoSingSang
59分钟前
1
0
增加 PostgreSQL 服务进程的最大打开文件数

https://serverfault.com/questions/628610/increasing-nproc-for-processes-launched-by-systemd-on-centos-7 要在systemd的配置里加才行...

helloclia
今天
2
0
组合模式在商品分类列表中的应用

在所有的树形结构中最适合的设计模式就是组合模式,我们看看常用商品分类中如何使用。 先定义一个树形结构的商品接口 public interface TreeProduct { List<TreeProduct> allProducts(...

算法之名
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部