如果我理解您的问题,不变性似乎与此处无关。您只是在询问线程是否会看到对共享对象的更新。
[Edit] 在交换 cmets 之后,我现在看到您还需要在执行某些操作时保留对共享单例状态的引用,然后设置状态以反映该操作。
和以前一样,好消息是提供此意志也必然会解决您的内存一致性问题。
您不必定义单独的同步 getState 和 updateState 方法,而是必须在不被中断的情况下执行所有三个操作:getState、yourAction 和 updateState。
我可以看到三种方法:
1) 在 GlobalStateCache 中的单个同步方法中执行所有三个步骤。 在 GlobalStateCache 中定义一个原子 doActionAndUpdateState 方法,当然在您的 state 单例上同步,这将采用函子对象做你的动作。
2) 将 getState 和 updateState 作为单独的调用,并更改 updateState 以确保状态自获取后未更改。 定义 getState 和 @987654332 @ 在 GlobalStateCache 中。 checkAndUpdateState 将采用从 getState 获得的原始状态调用者,并且必须能够检查自您获得后状态是否已更改。如果它已经发生了变化,您需要做一些事情让调用者知道他们可能需要恢复他们的操作(取决于您的用例)。
3) 在 GlobalStateCache 中定义一个getStateWithLock 方法。这意味着您还需要确保调用者释放他们的锁。我会创建一个显式的releaseStateLock 方法,并让您的updateState 方法调用它。
其中,我建议不要使用第 3 条,因为如果出现某些类型的错误,它会让您很容易锁定该状态。我也建议(虽然不太强烈)反对#2,因为它会在状态发生变化的情况下产生复杂性:你只是放弃行动吗?你重试吗?它必须(可以)恢复吗?我支持 #1:单一同步原子方法,它看起来像这样:
public interface DimitarActionFunctor {
public void performAction();
}
GlobalStateCache {
private MyImmutableState state = MyImmutableState.newInstance(null, null);
public MyImmutableState getState {
synchronized(state) {
return state;
}
}
public void doActionAndUpdateState(DimitarActionFunctor functor, State currentState, Args newArgs){
synchronized(state) {
functor.performAction();
state = MyImmutableState.newInstance(currentState, newArgs);
}
}
}
}
Caller 然后为动作构造一个函子(DimitarActionFunctor 的一个实例),并调用 doActionAndUpdateState。当然,如果动作需要数据,您必须定义函子接口以将该数据作为参数。
我再次指出这个问题,不是为了实际的差异,而是为了它们在内存一致性方面的工作方式:Difference between volatile and synchronized in Java