Java 中的同步 Get 方法

Mar*_*ark 1 java synchronization

这可能看起来像迂腐,但实际上是我在质疑我的基本假设..:)

关于同步方法的java文档中,有以下示例:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}
Run Code Online (Sandbox Code Playgroud)

synchronized该方法真的需要关键字吗value?当然,这是原子性的,无论在其他线程上调用相关方法之前还是之后检索该值都没有什么区别?以下就足够了:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public int value() {
        return c;
    }
}
Run Code Online (Sandbox Code Playgroud)

我明白,在更复杂的情况下,如果要访问多个私有变量,那么是的,这是必要的 - 但在这种简单的情况下,可以安全地假设这可以简化吗?

另外,我认为存在这样的风险:未来的修改可能需要同步 value 方法,这可能会被忘记,从而导致错误等,所以也许这在某种程度上算作防御性编程,但我在这里忽略了这一方面。 :)

dka*_*zel 5

是的,synchronized 确实是必需的value()。否则,线程可以调用value()并得到过时的答案。

当然这是原子的

对于整数,我相信是这样,但如果 value 是 alongdouble,则不是。甚至有可能只看到该字段中的某些位已更新!

在其他线程上调用相关方法之前或之后检索值没有什么区别吗?

取决于您的用例。通常这确实很重要。

value()如果未同步,某些静态分析软件(例如 FindBugs)会将这段代码标记为没有正确同步。

  • 如果没有同步,JVM 就可以进行各种优化。例如,假设您有一个循环 `while (counter.get() == 0) { /* wait or some */ }`。您会期望另一个线程上的增量会释放该锁,对吗?如果 getter 未同步,JVM 可以自由(并且通常会)优化 getter 以从本地寄存器读取,因此永远看不到任何增量。 (3认同)