【问题标题】:Mix volatile and synchronized as a read-write lock混合 volatile 和 synchronized 作为读写锁
【发布时间】:2010-11-27 02:40:32
【问题描述】:

考虑一个有大量线程读取和少量线程写入的原始类型变量,下面的代码会正常工作吗?

如果可以,它是否提供比 1) 更好的性能。在所有方法上声明同步; 2)。使用显式的 ReadWriteLock?

这是一种常见的模式吗?如果不是,这种情况下通常使用什么模式?

目前这对我来说很好用,但我觉得同时使用 volatile 和 synchronized 有点多余。

private volatile int value = 1;

public void func1()
{
    if (value == 1) {
        // do something
    }
}

public void func2()
{
    if (value == 2) {
        // do something
    }
}

public void func3()
{
    if (value == 3) {
        // do something
    }
}

public synchronized void increase()
{
    if (value < 10) value++;
}

public synchronized void decrease()
{
    if (value > 0) value--;
}

【问题讨论】:

    标签: java concurrency volatile synchronized readwritelock


    【解决方案1】:

    是的,这很常见,至少在一定程度上是这样:)

    这篇 IBM 文章中描述了您使用的模式 -> http://www.ibm.com/developerworks/java/library/j-jtp06197/index.html

    (模式#5,廉价的读写锁技巧)

    【讨论】:

    • +1 篇优秀文章,任何想要更好地理解 volatile 的人的“必读”
    • 阅读易失锁和同步锁让我思考,为什么我们不需要两者?如果我只使用同步的 setter 和 getter 并且不将变量设置为 volatile,则操作将是原子的,但我如何确定线程看到的是实际值而不是 CPU 缓存中的值?
    【解决方案2】:

    考虑一个有大量线程读取和少量线程写入的原始类型变量,下面的代码会正常工作吗?

    我想是的。

    如果可以,它是否提供比 1) 更好的性能。在所有方法上声明同步; 2)。使用显式的 ReadWriteLock?

    我认为是这样,前提是读取操作的数量超过写入请求。然而:

    • 除非这个计数器是高度竞争的,否则它可能无关紧要。除非您有证据表明它是(或将成为)瓶颈,否则不要浪费时间对某项进行微观优化。
    • 如果它对您来说真的很重要,请对其进行基准测试。
    • 如果相对性能取决于 JVM 版本/补丁级别、JVM 选项和硬件,请不要感到惊讶;例如处理器数量和内存架构。

    这是一种常见的模式吗?如果不是,这种情况下通常使用什么模式?

    我不知道这是否普遍。但我的直觉是,最常见的方法是只使用常规同步,而不用担心它。除非您正在处理高度竞争的数据结构,否则各种方法之间的性能差异对整体应用程序性能来说是微不足道的。

    【讨论】:

      【解决方案3】:

      我确信它提供了更好的性能,因为没有锁定,但它是否正确取决于代码的意图。当然,行为与同步情况不同。行为是否类似于锁定情况取决于您锁定的位置。

      【讨论】:

        最近更新 更多