我多次看到像这样的结构:
class OneTimeWriter {
volatile Object o;
void synchronized set(Object o) {
if(this.o == null) this.o = o;
}
Object get() {
return this.o;
}
}
我们在synchronized
本身的开头/结尾处读/写膜。那么,我们可以从o中删除volatile
,因为synchronized
本身有释放/获取语义吗?
答案 0 :(得分:1)
除非get
也是synchronized
,否则不会;否则,在设置者将非null
放入字段和get
调用之间的关系之前没有发生过。
答案 1 :(得分:1)
同步不是绝对的;它总是相对于另一个动作。对于synchronized
块,同步是在一个synchronized
块的关闭和同一对象上的后续块的打开之间。
由于您的get
方法未使用synchronized
,因此在它与set
方法之间没有建立先发生关系。由于重新排序,获取线程可以读取由setter放入的部分设置对象。例如,如果您输入("Foo", 123)
,获取线程可以读取与具有状态(null, 123)
相同的对象:123
状态存在,但"Foo"
状态没有还没写完(或冲到这个核心的记忆等)。
除了synchronized
块之外,在写volatile
字段和随后读取同一字段之间会发生另一种形式的同步。那个 - 而且只有那个 - 提供了在这种情况下你需要的事先发生的关系。设置器中的synchronized
块仅确保this.o
未设置两次,仅此而已。