StampedLock 如何对锁请求进行排队?
Posted
技术标签:
【中文标题】StampedLock 如何对锁请求进行排队?【英文标题】:How does StampedLock queue lock requests? 【发布时间】:2018-10-13 19:13:44 【问题描述】:我正在研究基于 Java8 的 StampedLock
(javadoc here) 锁定缓存,但尽管阅读了 StampedLock Idioms 之类的文章,但我在网上找不到令人信服的实现。
在对ReentrantReadWriteLock
不允许将读锁升级为写锁感到震惊之后,我对 Java 的多线程和并发产品感觉不太乐观,随后又难以找到一个有信誉的替代解决方案.
我的问题是,没有明确的声明可以减轻我对StampedLock
会在有读取请求排队时无限期阻止写入请求的担忧。
查看文档,有 2 个 cmets 引起了我的怀疑。
来自Javadoc:
StampedLock 的调度策略并不一致 读者超过作者,反之亦然。所有的“尝试”方法都是尽力而为 并且不一定符合任何调度或公平政策。
来自source code:
* These rules apply to threads actually queued. All tryLock forms
* opportunistically try to acquire locks regardless of preference
* rules, and so may "barge" their way in. Randomized spinning is
* used in the acquire methods to reduce (increasingly expensive)
* context switching while also ....
所以它暗示了一个读写锁队列,但我需要阅读和消化整个 1500 行源代码才能确定它。
我认为它一定存在,因为我找到了 good benchmarking article,它表明 StampedLock
是进行多次读取/少量写入的方式。但是,由于缺乏在线报道,我仍然很担心。
从根本上说,我想我希望有一个实现,我可以在 javadoc 之后即插即用,但最后我还是在网上扎根,想知道为什么在任何地方都没有循环 StampedLock#tryOptimisticRead()
的示例 -即使code from the benchmark article 也不这样做。
Java 并发这么难还是我遗漏了一些明显的东西?
【问题讨论】:
【参考方案1】:“Java 并发这么难还是我遗漏了一些明显的东西?”
Java 并发是否比(例如)C++ 或 Python 并发更难,这是一个见仁见智的问题。
但是,是的,在任何允许不同线程直接更新共享数据结构的语言中,并发都是困难的2。 (仅)支持类似 CSP 的并发的语言更容易理解和推理。
参考:
https://en.wikipedia.org/wiki/Communicating_sequential_processes就您关于公平的观点而言,Java 中的大多数锁定形式确实不能保证公平。事实上,与线程调度有关的许多事情(故意)松散地指定。但是编写避免这些问题的代码并不难……一旦您了解了这些库以及如何使用它们。
关于StampedLock
行为的具体问题。
我的问题是,没有明确的声明可以减轻我对
StampedLock
会在有读取请求排队时无限期阻止写入请求的担忧。
没有这样的声明3 因为这样的行为是可能的。它源自对StampedLock
API 文档的仔细阅读。例如,它说:
“
StampedLock
的调度策略并不总是优先选择读者而不是作者,反之亦然。”
简而言之,没有什么可以保证不定时的writeLock
最终会获得锁。
如果您需要断然避免读者导致写者饿死的情况,那么不要使用writeLock
和readLock
。您可以使用tryOptimisticRead
而不是readLock
。或者您可以设计和实现不同的同步机制。
最后,您似乎暗示StampedLock
应该提供一种直接处理您的场景的方法和/或该文档应该专门向非专家用户解释如何处理它.我提请人们注意这一点:
“StampedLocks 被设计用作开发线程安全组件的内部实用程序。”。
您很难找到相关示例,这不是 javadocs 的错。如果有的话,它支持这个 API 是为专家提供的推断......
1 - 我认为 Java 的并发支持至少比大多数其他同类语言更容易推理。 Java 内存模型(JLS 的第 17.4 章)已详细说明,Goetz 等人的“Java Concurrency In Practice”很好地解释了并发编程的来龙去脉。 2 - .... 适用于大多数程序员。 3 - 如果这对您来说不够明确,请给自己写一个示例,其中存在(模拟的)无限大序列的读取请求和多个读取器线程。运行它并查看写入器线程是否停止,直到读取请求全部耗尽。
【讨论】:
以上是关于StampedLock 如何对锁请求进行排队?的主要内容,如果未能解决你的问题,请参考以下文章
Glide 是不是对每个图像请求进行排队?滚动时Recyclerview加载非常慢