文档章节

golang非阻塞锁的简单实现

吾爱
 吾爱
发布于 2017/04/04 12:19
字数 408
阅读 770
收藏 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~

 

© 著作权归作者所有

上一篇: 学习笔记
吾爱
粉丝 143
博文 272
码字总数 91680
作品 0
后端工程师
私信 提问
加载中

评论(0)

Golang 高效实践之并发实践channel篇

前言 在我前面一篇文章Golang受欢迎的原因中已经提到,Golang是在语言层面(runtime)就支持了并发模型。那么作为编程人员,我们在实践Golang的并发编程时,又有什么需要注意的点呢?下面我会...

osc_ai011l20
04/16
14
0
详解golang net之netpoll

golang版本1.12.9;操作系统:readhat 7.4 golang的底层使用epoll来实现IO复用。netPoll通过pollDesc结构体将文件描述符与底层进行了绑定。netpoll实现了用户层面的与底层网络IO相关的gorou...

osc_5iujocsb
2019/09/20
6
0
golang 面试题(从基础到高级)

Golang面试问题汇总 通常我们去面试肯定会有些不错的Golang的面试题目的,所以总结下,让其他Golang开发者也可以查看到,同时也用来检测自己的能力和提醒自己的不足之处,欢迎大家补充和提交新...

osc_panqs2jh
2019/03/14
15
0
基于 PHP 协程的网络服务框架--Zan PHP Framework

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

匿名
2017/06/21
2.6K
6
Golang 实现 Redis(3): 实现内存数据库

本文是 golang 实现 redis 系列的第三篇, 主要介绍如何实现内存KV数据库。本文完整源代码在作者Github: HDT3213/godis db.go 是内存数据库的主要源文件,db.Exec 方法会从协议解析器中获得命...

-Finley-
03/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

web前端入门知识大全:系统路线,各类要点解析

一、WEB前端是什么? 使用HTML/CSS/JS以及更多的框架技术,编写网站页面、App应用、小程序、2D&3D游戏、Web VR&AR等应用,通过内容设计、交互动画、数据操作构建项目与用户的交互界面。前端开...

梦想编程
41分钟前
11
0
一个软件测试7年的程序员,讲述自己两年突破瓶颈的经验,关注这些能让你少走弯路。

突破自己的技术瓶颈并不是一蹴而就,还是需要看清楚一些东西,这里也有一些经验和见解跟大家分享一下。同样是职场人士,我也有我的经历和故事。在工作期间,我有过2年加薪7次的小小“战绩”(...

爱码小哥
51分钟前
8
0
ReentrantLock 读写锁

写写共享 读写互斥 写写互斥 适合读多的业务 提高效率 import java.util.concurrent.locks.ReentrantReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;......

Joker上上签
53分钟前
19
0
IM即时通讯 时间处理1

function formatDate(now) { let date = new Date(now); let Y = date.getFullYear() + '-'; let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getM......

lsy999
53分钟前
9
0
rust tokio mpsc 异步发送数据

启动两个异步任务,一个阻塞在键盘输入。一个间歇的读取通道,有数据就输出。在快速输入的时候会卡住,因为 mpsc 的 buffer 设置为了 5。 代码如下: use std::io;use tokio::task;use to...

Anunakee
54分钟前
16
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部