Java 一个生产者一个状态对象有多个消费者

Java 一个生产者一个状态对象有多个消费者,java,java-8,locking,synchronized,producer-consumer,Java,Java 8,Locking,Synchronized,Producer Consumer,我有一位制片人: maintains ref StateRef to object StateObj implements method modify() method which modifies StateObj implements getRef() method which will be used by consumers 我有多个消费者,他们获取StateObj的ref并读取StateObj (生产者:修改stateObj,消费者读取(仅)stateObj) 所以,在典型的设计中,

我有一位制片人:

maintains ref StateRef to object StateObj
implements method modify() method which modifies StateObj
implements getRef() method which will be used by consumers
我有多个消费者,他们获取StateObj的ref并读取StateObj

(生产者:修改stateObj,消费者读取(仅)stateObj)

所以,在典型的设计中,我需要由使用者读取锁,由生产者写入锁,这可能是高效的

但由于只有一个编写器,我将modify()方法编写为:

1. Ref refToCloneCopy = StateRef.clone()
2. update(refToCloneCopy)
3. StateRef = refToCloneCopy
优点:我不必对消费者强制执行读锁

我想确保在第三步未完成之前,“getRef()”将继续将ref返回到StateObj,在第三步之后,“getRef”将把ref返回到newState/ClonedObj

没有种族条件或一致性的要求,即,如果一半消费者收到oldState的ref,而另一半消费者收到newState的ref(clonedObj),则OK。但是getRef不应该返回一些奇怪的ref值,它应该返回oldState或newstate

我用Java8来做这个。。。有什么最好的方法可以有效地处理这一问题,而不会在消费者或生产者方面造成太多(或没有)锁定

更新:
即使我们决定在上面的第三步中使用锁,我想确保写入者/制作者的锁请求比消费者的锁请求具有更高的优先级,前提是您可以保证在创建新状态时返回旧状态,然后,您可以简单地将克隆和修改作为方法级变量,并将其分配给该方法末尾的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的值,而看不到生产者线程的更改。它还可以防止编译器重新排序代码。

但我是否需要在stateref=newobj的最后一个stmt处锁定,因为当stateref中的地址值改变时,这不是原子操作,或者Java原子中的是ref赋值?@sameer赋值应该可以。如果get和set需要是原子的,那么volatile是不够的。例如,如果您要执行类似于检查stateRef是否为null的操作,并仅在modify中设置它,那么您将需要synchronized或AtomicReference。但是在你陈述的用例中,volatile就足够了。