1

我在这里遇到了一个非常奇怪的问题,对象状态错误,我在使用Handler.postDelayed. 我使用它来安排 2D 绘图的绘图调用,并且此绘图代码检查某些状态字段(如整数和布尔值)。

现在,这些状态字段可能会我安排抽奖后发生变化,但是由于所有方法,甚至延迟调用都在同一个线程上执行(对吗?),因此不应存在由于共享状态而导致的可见性问题。

尽管如此,我有时会看到例如false在预定抽签中的标志,即使它不可能是,因为我true在安排抽签之前将其设置为并且不再触摸它。一些伪示例代码:

public void scheduleDraw() {
    boolean flag = true;
    handler.postDelayed(runnable);
}

runnable = new Runnable() {
    public void run() {
        // flag is false here
    }
}

这怎么可能发生?我不完全确定 Android 是如何实现这些消息循环的,但我检查了调度绘制的方法和调度方法本身的线程标识,它们都在同一个线程(主 UI 线程)上调用。

这让我发疯,有人可以帮忙吗?

更新 我注意到问题是由于内部类检查了一次标志,而外​​部类检查了一次。绘制代码作为内部类的一部分运行,并看到标志处于正确状态,而外部类,即使它包含对内部类实例的引用,总是将标志视为假(不正确的状态)。我仍然不明白这个问题,但它似乎与类嵌套有关?

4

2 回答 2

1

我可以在这里看到几个问题。

首先,在您的示例代码中,您将 flag 声明为 scheduleDraw() 中的本地范围变量。我什至看不到 runnable 如何访问它。

假设这只是一个错字并且该标志是一个类变量......简单地将布尔值设置为 true 并不意味着所有线程都会立即看到相同的值。在 Java 中,一些变量写入可以在线程本地缓存,这意味着其他线程实际上会看到不一致的值。避免这种情况的一种方法是声明一个变量 volatile。例如:

private volatile boolean flag;

这样做会告诉 Java 运行时这个变量永远不应该在线程本地缓存,所有的读取和写入都应该直接进入“主内存”。

另一种解决方案是使用java.util.concurrent.atomic 包中的AtomicBoolean实例

private AtomicBoolean flag = new AtomicBoolean();
...
flag.set(true);
于 2012-08-09T19:28:11.437 回答
0

我发现了问题:外部类保留了对内部类的引用,其中几个实例可以同时处于活动状态(并切换)。由于它们共享外部类的处理程序,外部类有时会在处理程序回调中收到来自刚刚变为非活动的处理程序回调的延迟消息。

我现在不再在外部类和内部类之间共享任何变量。

非常感谢您的帮助!赞赏。

于 2012-08-09T21:06:38.367 回答