我有一个制作人:
maintains ref StateRef to object StateObj
implements method modify() method which modifies StateObj
implements getRef() method which will be used by consumers
我有多个消费者获得对StateObj的参考并阅读StateObj
(生产者:修改stateObj,消费者读取(仅)stateObj)
所以在典型的设计中,我需要消费者的读锁定和生产者的写锁定,这可能是无效的。
但由于只有一个编写器,我将modify()方法编写为:
1. Ref refToCloneCopy = StateRef.clone()
2. update(refToCloneCopy)
3. StateRef = refToCloneCopy
优点:我不必对消费者强制执行读锁定。
我想确保直到第3步没有完成“getRef()”将继续返回ref到StateObj并且在步骤3之后“getRef”将返回ref给newState / ClonedObj
没有竞争条件或一致性的要求,即如果一半消费者收到旧州的参考,而另一半消费者接受参考newState(clonedObj),则可以。但是getRef不应该返回一些奇怪的ref值,它应该返回oldState或new State。
我正在使用Java8。 ...在消费者方或生产方没有太多(或否)锁定的情况下,最好的方法是有效地处理这个问题吗?
更新: 即使我们决定在上面的第3步中采取锁定,我想确保作者/制作人的锁定请求优先于消费者的锁定请求
答案 0 :(得分:1)
如果保证在创建新状态时可以返回旧状态,那么您可以简单地将克隆和修改作为方法级变量并将其分配给该结尾处的stateRef字段。方法。看起来你提到的修改应该符合要求。但有一点需要确定的是将stateRef声明为volatile。像这样:
class Producer {
private volatile StateObj stateRef;
StateObj getRef() {
return stateRef;
}
void modify() {
// Leave the instance field alone until modification is done
StateObj newObj = (StateObj) stateRef.clone();
// Do stuff to the new local variable reference. If any consumers
// call getRef while this is happening they get the stateRef value and
// not the newObj value.
// Once the newObj instance if fully initialized, set it as
// the stateRef instance.
stateRef = newObj;
}
}
由于stateRef仅在modify方法的最末端被更改,并且它被简单地设置为新的,已经完全初始化的StateObj实例,因此您不会让任何生成器使用者与该值发生冲突。请注意,volative关键字很重要,否则其他消费者线程可能会缓存stateRef的值而不会看到生产者线程的更改。它还可以防止编译器重新排序代码。