【问题标题】:One Producer Multiple Consumers for one state Object一个状态对象的一个​​生产者多个消费者
【发布时间】:2016-12-13 12:50:23
【问题描述】:

我有一位制作人:

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)

所以在典型的设计中,我需要消费者的读锁和生产者的写锁,这可能是低效的。

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

1. Ref refToCloneCopy = StateRef.clone()
2. update(refToCloneCopy)
3. StateRef = refToCloneCopy

优点:我不必对消费者强制执行读锁定。

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

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

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

更新: 即使我们决定在上面的第三步中锁定,我想确保作者/生产者的锁定请求应该比消费者的锁定请求具有更高的优先级

【问题讨论】:

    标签: java java-8 locking synchronized producer-consumer


    【解决方案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 的值而看不到生产者线程的更改。它还可以防止编译器重新排序代码。

    【讨论】:

    • 但是我是否需要在 stateref=newobj 的最后一个 stmt 锁定,因为当 stateref 中的地址值发生变化时,这不是原子操作
    • 或者Java中的ref赋值是原子的?
    • @sameer 分配应该没问题。如果 get 和 set 需要是原子的,那么 volatile 是不够的。例如,如果您要执行检查 stateRef 是否为 null 并仅在这种情况下在 modify 中设置它,那么您将需要同步或 AtomicReference。但是在您声明的用例中, volatile 就足够了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多