在《Java并发性实践》一书中附加了以下代码:
public class Counter {
private long value = 0;
public synchronized long getValue() {
return value;
}
public synchronized void increment() {
++value;
}
}
这里是long类型的value字段,以及同步的读和增量方法。
我是否正确理解了read方法的同步只需要用于long和double类型,因为它们不是原子类型?如果字段值是int类型,那么read方法的同步将是不必要的?
需要同步getValue
方法
在Java中,synchronized
关键字为您提供了可见性和原子性保证。根据经验,您应该记住编译器开发人员和CPU供应商可以自由地进行优化,例如内存重新排序或将寄存器中的变量缓存为,只要优化后的程序在单线程环境中保持不变。
现在让我们看看当不同的线程调用getValue
和increment
方法时,getValue
不再同步时会发生什么。从JVM的角度来看,任何只读取value
而从不通过increment
方法更新它的线程实际上总是读取相同的常量值。因此,在读取线程中,JVM可能会选择将变量保存在寄存器中,而不再从内存中读取它!
正如注释所建议的,可以通过将value
的类型从int
更改为AtomicInteger
来删除synchronized
关键字。但是,即使您不想使用AtomicInteger
,您也可以这样重写您的类:
public class Counter {
private volatile int value = 0;
public int getValue() {
return value;
}
public synchronized void increment() {
++value;
}
}
volatile
关键字将确保可见性,并且读取不再需要任何锁定。我建议检查这些参考资料以了解更多关于Java内存模型的信息:
https://jenkov.com/tutorials/java-concurrency/index.html
https://docs.oracle.com/javase/specs/jls/se17/html/jls - 17. - html