【问题标题】:How does StampedLock queue lock requests?StampedLock 如何对锁请求进行排队?
【发布时间】: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 并发这么难还是我遗漏了一些明显的东西?

【问题讨论】:

    标签: java multithreading concurrency locking


    【解决方案1】:

    “Java 并发这么难还是我遗漏了一些明显的东西?”

    Java 并发是否比(例如)C++ 或 Python 并发更难,这是一个见仁见智的问题。

    但是,是的,在任何允许不同线程直接更新共享数据结构的语言中,并发都是困难的2。 (仅)支持类似 CSP 的并发的语言更容易理解和推理。

    参考:


    就您关于公平的观点而言,Java 中的大多数锁定形式确实不能保证公平。事实上,与线程调度有关的许多事情(故意)松散地指定。但是编写避免这些问题的代码并不难……一旦您了解了这些库以及如何使用它们。


    关于StampedLock 行为的具体问题。

    我的问题是,没有明确的声明可以减轻我对StampedLock 会在有读取请求排队时无限期阻止写入请求的担忧。

    没有这样的声明3 因为这样的行为是可能的。它源自对StampedLock API 文档的仔细阅读。例如,它说:

    StampedLock 的调度策略并不总是优先选择读者而不是作者,反之亦然。”

    简而言之,没有什么可以保证不定时的writeLock 最终会获得锁。

    如果您需要断然避免读者导致写者饿死的情况,那么不要使用writeLockreadLock。您可以使用tryOptimisticRead 而不是readLock。或者您可以设计和实现不同的同步机制。


    最后,您似乎暗示StampedLock 应该提供一种直接处理您的场景的方法和/或该文档应该专门向非专家用户解释如何处理它.我提请人们注意这一点:

    StampedLocks 被设计用作开发线程安全组件的内部实用程序。”。

    您很难找到相关示例,这不是 javadocs 的错。如果有的话,它支持这个 API 是为专家提供的推断......


    1 - 我认为 Java 的并发支持至少比大多数其他同类语言更容易推理。 Java 内存模型(JLS 的第 17.4 章)已详细说明,Goetz 等人的“Java Concurrency In Practice”很好地解释了并发编程的来龙去脉。
    2 - .... 适用于大多数程序员。
    3 - 如果这对您来说不够明确,请给自己写一个示例,其中存在(模拟的)无限大序列的读取请求和多个读取器线程。运行它并查看写入器线程是否停止,直到读取请求全部耗尽。

    【讨论】:

      猜你喜欢
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2021-08-24
      • 1970-01-01
      • 1970-01-01
      • 2011-09-01
      • 2011-06-14
      • 1970-01-01
      相关资源
      最近更新 更多