一个状态对象的一个​​生产者多个消费者

One Producer Multiple Consumers for one state Object

我有一位制作人:

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()" 将继续 return 引用 StateObj 并且在第 3 步 "getRef" 之后 return 引用newState/ClonedObj

没有竞争条件或一致性的要求,即如果一半消费者接收对 oldState 的 ref 而另一半消费者接收对 newState(clonedObj) 的 ref 就可以了。但是 getRef 不应该 return 一些奇怪的 ref 值,它应该 return oldState 或 new State。

我为此使用 Java8。 ...在消费者端或生产者端没有太多(或没有)锁定的情况下有效处理此问题的最佳方法是什么?

更新: 即使我们决定在上面的第 3 步中锁定,我也想确保 writer/producer 的锁定请求优先于消费者

的锁定请求

如果您保证在创建新状态时可以 return 旧状态,那么您可以简单地将克隆和修改作为方法级变量并将其分配给 stateRef该方法末尾的字段。看起来你提到的 modify 应该符合要求。不过,需要确定的一件事是将 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 仅在修改方法的最后更改,并且它只是设置为新的、已经完全初始化的 StateObj 实例。请注意,volative 关键字很重要,否则其他消费者线程可能会缓存 stateRef 的值,而看不到来自生产者线程的更改。它还可以防止编译器重新排序代码。