【问题标题】:Convert synchronized methods to non-blocking algorithm将同步方法转换为非阻塞算法
【发布时间】:2016-04-18 15:11:33
【问题描述】:

随便找一些关于非阻塞算法的资料,所以想在实践中使用。我将一些代码从同步更改为非阻塞,所以我想问一下我是否将所有内容都正确并保存了以前的功能。

同步代码:

protected PersistentState persistentState;
protected ClassConstructor(final ID id)
{
    super(id);
    this.persistentState = PersistentState.UNKNOWN;
}
public final synchronized PersistentState getPersistentState()
{
    return this.persistentState;
}

protected synchronized void setPersistentState(final PersistentState newPersistentState)
{
    if (this.persistentState != newPersistentState)
    {
        this.persistentState = newPersistentState;
        notifyPersistentStateChanged();
    }
}

我在非阻塞算法中的替代方案:

     protected AtomicReference<PersistentState> persistentState;
  protected ClassConstructor(final ID id)
    {
        super(id);
        this.persistentState = new AtomicReference<PersistentState>(PersistentState.UNKNOWN);
    }
   public final PersistentState getPersistentState()
    {
        return this.persistentState.get();
    }

    protected void setPersistentState(final PersistentState newPersistentState)
    {
        PersistentState tmpPersistentState;
        do
        {
            tmpPersistentState = this.persistentState.get();
        }
        while (!this.persistentState.compareAndSet(tmpPersistentState, newPersistentState));
        // this.persistentState.set(newPersistentState); removed as not necessary 
        notifyPersistentStateChanged();
    }

我做的一切都是正确的,还是我错过了什么?对代码和使用非阻塞方法设置 abject 有什么建议吗?

【问题讨论】:

  • 你不应该使用 "this.persistentState.set(newPersistentState)" 作为 compareAndSet 更新persistentState的值
  • compareAndSet 只有在将值设置为 newPersistentState 后才会跳出 while 循环,因此不需要像哈恩提到的那样再次将其设置为 newPersistentState。如果需要,那么这将是一种检查然后采取行动的方式,容易出现过时的数据问题。幸好不是。

标签: java multithreading synchronization nonblocking atomicreference


【解决方案1】:

取决于thread-safe 的含义。如果两个线程同时尝试写入,你想发生什么?是否应该随机选择其中一个作为正确的新值?

这是最简单的。

protected AtomicReference<PersistentState> persistentState = new AtomicReference<PersistentState>(PersistentState.UNKNOWN);

public final PersistentState getPersistentState() {
    return this.persistentState.get();
}

protected void setPersistentState(final PersistentState newPersistentState) {
    persistentState.set(newPersistentState);
    notifyPersistentStateChanged();
}

private void notifyPersistentStateChanged() {
}

在所有情况下这仍然会调用notifyPersistentStateChanged,即使状态没有改变。您需要决定在这种情况下应该发生什么(一个线程生成 A -> B,另一个线程生成 B -> A)。

但是,如果您只需要调用 notify 并成功转换值,您可以尝试如下操作:

 protected void setPersistentState(final PersistentState newPersistentState) {
    boolean changed = false;
    for (PersistentState oldState = getPersistentState();
            // Keep going if different
            changed = !oldState.equals(newPersistentState)
            // Transition old -> new successful?
            && !persistentState.compareAndSet(oldState, newPersistentState);
            // What is it now!
            oldState = getPersistentState()) {
        // Didn't transition - go around again.
    }
    if (changed) {
        // Notify the change.
        notifyPersistentStateChanged();
    }
}

【讨论】:

  • 我只需要在更改时通知。顺便说一句,我是否理解在我的情况下,如果线程想要设置相同的值,我将得到无限循环?
  • @Edgar - 没有。如果 tmoPersistentState 与 newPersistentState 相同,您的循环就可以正常工作。只要 this.persistentState 与 tmpPersistentState 相同,它将返回 true 并突破。不应该有无限循环。
猜你喜欢
  • 2023-03-12
  • 2015-08-17
  • 2018-04-06
  • 2023-03-14
  • 2013-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多