android - 处理程序发布的 Runnable 看到错误的对象状态(竞争条件?)

标签 android concurrency message-loop

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

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

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

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

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

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

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

更新 我注意到问题是由于内部类检查了一次标志,外部类检查了一次。绘制代码作为内部类的一部分运行,并看到标志处于正确的状态,而外部类,即使它包含对内部类实例的引用,也总是将标志视为 false(不正确的状态)。还是没看懂,不过好像跟类嵌套有关?

最佳答案

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

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

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

private volatile boolean flag;

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

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

private AtomicBoolean flag = new AtomicBoolean();
...
flag.set(true);

关于android - 处理程序发布的 Runnable 看到错误的对象状态(竞争条件?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11889865/

相关文章:

java - Android应用程序上下文参数

android-为 Chip 文本添加顶部填充

Erlang 消息循环

Qt QTcpSocket : How to prevent dead lock in readyRead signal?

android - 取消共享元素转换

android - Android 中的 ActionScript 套接字

multithreading - Hibernate的线程问题

JAVA的 future 是运行?

django - 在 10 个并发 uwsgi worker 上锁定 Django DB - 怎么做?

C# - 等待 WinForms 消息循环