commonsware5.9事件总线示例中的线程安全问题



我有一个线程安全问题/问题关于CommonsWare 5.9事件总线的例子。

在我看来,model ArrayList从多个线程访问的方式有问题。如果这有效,我很想知道为什么。

此代码执行model的声明、初始化和填充。

private static final String[] items= { "lorem", "ipsum", "dolor",
  "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
  "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
  "vel", "erat", "placerat", "ante", "porttitor", "sodales",
  "pellentesque", "augue", "purus" };
private ArrayList<String> model=new ArrayList<String>();
private boolean isStarted=false;
@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setRetainInstance(true);
  if (!isStarted) {
    isStarted=true;
    new LoadWordsThread().start();
  }
}
public ArrayList<String> getModel() {
  return(model);
}
class LoadWordsThread extends Thread {
  @Override
  public void run() {
    for (String item : items) {
      if (!isInterrupted()) {
        model.add(item);
        EventBus.getDefault().post(new WordReadyEvent());
        SystemClock.sleep(400);
      }
    }
  }
}

它每400毫秒唤醒一次,并向model添加一个条目。model的使用有点复杂,因为我没有现成的代码可以发布。它在ArrayAdapter的某个地方。模型的消费是由对ArrayAdapter.notifyDataSetChanged()的调用触发的。

我的问题是model是在一个线程(不是Android UI线程)中写入的,但消费发生在UI线程上。model ArrayList的所有元素都是不可变的,这很有帮助,但对我来说似乎仍然不对。

如果这段代码实际上是正确的,我想知道为什么。谢谢你,李。

更新:

我认为我的问题不在于事件总线部分。我想我明白了。它几乎更多的是一个java问题,我在该模型中被写入一个线程(worker线程,上面的代码),而理论上它可以同时从另一个线程(UI线程)中读取。在我看来,在模型上需要某种类型的并发访问控制。一个同步块或并发ArrayList。但模型的最终消费者是我在应用程序中无法控制的代码,它在ArrayAdapter某处。我不能给它添加同步。一旦用模型初始化ArrayAdapter, ArrayAdapter就拥有它,并将从UI线程访问它。我不确定非ui线程可以以这种方式修改模型。

你是正确的-这个示例应用程序是有缺陷的。我试图尽量减少代码,但我做得太过了。

需要做的两个修改是:

  1. AsyncDemoFragment应该在模型ArrayList<String>的副本上工作,从当时的模型初始化,而不是实际上模型

  2. 我应该在WordReadyEvent中提供单词,以允许AsyncDemoFragment更新其模型副本,除了触发notifyDataSetChanged()

这将允许后台线程在后台线程上更新和维护模型主副本,让UI线程知道所需的更改,并允许UI线程检索该模型的副本供UI使用。

在其他情况下,拥有共享的同步模型也不是不可能的。在这种情况下,这是不切实际的,除非kcoppock建议创建一个定制的适配器类,在这种情况下,这就像用别克打苍蝇一样。

我将在下次图书更新中修复这个问题。

顺便说一句,我问你是否读过这一章的原因很简单,因为有些人只根据审查回购来问问题,我想知道你是否读过样本附带的材料。我的评论可以被理解为,如果你读了这一章,你就会得到你的问题的答案,我绝对不是那个意思。如果我糟糕的措辞给你带来了任何问题,我向你道歉。

谢谢你指出这个问题!

最新更新