将volatile和synchronized混合使用作为读写锁

7
考虑一个具有大量线程读取和少量线程写入的原始类型变量,以下代码是否能正确工作?
如果可以,它是否比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--;
}
3个回答

6

1
+1 优秀的文章,对于任何想更好地理解 volatile 变量的人来说都是“必读”的。 - Cerber
阅读关于volatile和synchronized锁的内容让我想到,为什么我们不需要两者都用呢?如果我只使用synchronized的setter和getter,而不将变量设置为volatile,那么操作将是原子性的,但我如何确保线程看到的是实际值而不是CPU缓存中的值呢? - mauron85

3
考虑一个原始类型变量,有很多线程读取和少量线程写入,下面的代码是否能正常工作?
我认为是这样的。
如果可以,它是否比以下方法提供更好的性能?1)在所有方法上声明同步;2)使用显式的ReadWriteLock?
我认为是这样的,前提是读操作超过写请求。然而:
除非该计数器高度争用,否则可能无关紧要。不要浪费时间微调某些东西,除非你有证据表明它(或将成为)瓶颈。
如果它确实对你很重要,请进行基准测试。
别惊讶于相对性能取决于JVM版本/补丁级别、JVM选项和硬件;例如处理器数量和内存架构。
这是一个常见的模式吗?如果不是,通常在这种情况下使用什么模式?
我不知道这是否常见。但我的直觉是,最常见的方法是只使用常规同步,不要担心它。除非您正在处理高度争用的数据结构,否则各种方法之间的性能差异对整体应用程序性能来说将是微不足道的。

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接