【问题标题】:Avoiding race condition in enum-based Finite State Machine在基于枚举的有限状态机中避免竞争条件
【发布时间】:2014-08-29 21:50:12
【问题描述】:

我有一个基于enum 的状态机。以下是说明我的状态结构和我遇到的问题的示例代码。

public enum LinkStates implements StuffDoneListener {

    ...

    DO_SOME_WORK {
        public void process() {
            ....
            ....
            someObject.startDoingSpecialStuff();
            outerClass.toState(WAIT_FOR_EVENT);
        }
    },


    WAIT_FOR_EVENT {
        public void process() {
            // does nothing
        }

        public void onSpecialStuffComplete() {

        }
    }

    ...

    // Default implementation of interface methods which individual states
    // may override at will
    public void onSpecialStuffComplete() {
    }

}

process() 方法是在状态更改时调用的方法。每个状态还倾向于覆盖各种侦听器方法以接收各种事件。

State DO_SOME_WORK 调用对象上的方法 (startDoingSpecialStuff()) 以使其执行一些冗长的工作。该对象在另一个非 UI Thread 上工作。完成后,通过onSpecialStuffComplete() 通知状态机,在调用该工作的原始线程上调用该状态机。这里明显的问题是,如果工作很快完成,可能会出现竞争条件,即 FSM 在侦听器回调触发后移动到WAIT_FOR_EVENT

对我来说“修复”这个问题非常简单,也许还可以通过覆盖DO_SOME_WORK 中的onSpecialStuffComplete(),这样如果它在那里得到通知,它就知道不必费心去WAIT_FOR_EVENT。或者我可以使用一个有点粗略的boolean 标志,WAIT_FOR_EVENT 在进入该状态后立即轮询以检查事件是否已经触发。

然而,我正在寻找一种更优雅、更强大的解决方案来解决这个一般问题。

我使用了Android 标记,尽管这可能被视为一般 Java 设计模式问题,以防万一我可以使用依赖于 Android 特定类的更好解决方案。

【问题讨论】:

  • 是否在您的“UI”线程上调用了 DO_SOME_WORK.process(与调用“onSpecialStuffComplete”的线程相同)?如果是这样,我看不到竞争条件。如果不是 - 是否有理由不能让 DO_SOME_WORK.process 反转其调用的顺序,以便在开始 specialStuff 之前 outerClass 处于 WAIT_FOR_EVENT 中?

标签: java android state-machine


【解决方案1】:

我认为DO_SOME_WORKWAIT_FOR_EVENT 可以合并。在“特殊内容”完成之前,不必发生状态转换:

public enum LinkStates implements StuffDoneListener {
    // ...

    START_SOME_WORK_AND_WAIT {
        public void process() {
            // ....
            someObject.startDoingSpecialStuff();
        }

        public void onSpecialStuffComplete() {
            outerClass.toState(EVENT_IS_COMPLETE);
        }
    },

    EVENT_IS_COMPLETE {
        public void process() {
            // ...
        }
        // ...
    }

    // ...

    public void onSpecialStuffComplete() {
    }
}

以这种方式编写时,我看不到竞争条件,因此假设它不会破坏未发布的内容,它应该可以正常工作。

【讨论】:

  • 非常感谢。虽然真正的代码要复杂得多,但你让我思考,从概念上讲,我现在有一些与此非常相似的东西。这里学到的要点是要小心状态的选择,并首先通过触发事件并在一个状态内接收后续回调来消除竞争条件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-30
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
  • 2019-06-12
相关资源
最近更新 更多