前言
asongGoGojavaGo
什么是可重入锁
java
假设现在有多个村民在水井排队打水,有管理员正在看管这口水井,村民在打水时,管理员允许锁和同一个人的多个水桶绑定,这个人用多个水桶打水时,第一个水桶和锁绑定并打完水之后,第二个水桶也可以直接和锁绑定并开始打水,所有的水桶都打完水之后打水人才会将锁还给管理员。这个人的所有打水流程都能够成功执行,后续等待的人也能够打到水。这就是可重入锁。
下图摘自美团技术团队分享的文章:
如果是非可重入锁,,此时管理员只允许锁和同一个人的一个水桶绑定。第一个水桶和锁绑定打完水之后并不会释放锁,导致第二个水桶不能和锁绑定也无法打水。当前线程出现死锁,整个等待队列中的所有线程都无法被唤醒。
下图依旧摘自美团技术团队分享的文章:
Go
javaReentrantLock
ReentrantLockAQSAQSstatusstatus0statusstatus == 0status1status != 0status+1statusstatus-1 == 0
总结一下实现一个可重入锁需要这两点:
- 记住持有锁的线程
- 统计重入的次数
统计重入的次数很容易实现,接下来我们考虑一下怎么实现记住持有锁的线程?
GoGoroutineGoGoGoroutineGoroutineGoroutineGoroutinepanicGo语言Goroutine IDruntime.StackGoroutine ID
goGoroutineGoroutine ID
Mutexhostgoroutine idrecursiongoroutinesync.CondCondGoroutinecondsync.Cond
- 构造函数
Lock
这里逻辑比较简单,大概解释一下:
GoroutineIDGoroutineresutsionGoroutineGoroutineGoroutinecond.wait
Unlock
大概解释如下:
GoroutinepanicGoroutinecond.Signal
github
Go
Go
举个例子,假设我们现在一段这样的代码:
F()G()
这样不仅避免了死锁,而且还对代码进行了解耦。这样的代码按照作用范围进行了分层,就像金字塔一样,上层调用下层的函数,越往上作用范围越大;各层有自己的锁。
Go
总结
Go
asong