3

我认为这不是一个简单的问题。我将简要介绍一下正在发生的事情。假设我们在文件 Byron.txt 中有一个数据源:

她走在美丽中,像
万里无云的星空和星空;
和所有最好的黑暗和光明
在她的容貌和她的眼睛里相遇:
如此柔和的温柔的光芒,
天堂拒绝艳丽的日子。

这段代码在 AsyncTask 中执行:

final ArrayList<Record> poem = new ArrayList<Record>();
final Object objectLock = new Object();
private Record rec = new Record();

@Override
protected Void doInBackground(Void... args) {
    String line = null;
    int i;
    int last;

    try {
        process = Runtime.getRuntime().exec("cat Byron.txt");
        bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()), 8192);

        synchronized (objectLock) {
            poem.clear();
            last = i = poem.size() - 1;
        }
        while(line = bufferedReader.readLine()) != null) {
            rec.setString(line);
            synchronized (objectLock) {
                last++;
                poem.add(last, rec);
            }

            while(!bPause && i < last) {
                i++;
                publishProgress(poem.get(i));
            }
        }
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
protected synchronized void onProgressUpdate(Record... m) {
    if(m.length > 0) {
        mContext.mTable.appendRow(m[0]);
    }

}

UI 中有一个 TableLayout ,每次我们得到一个新行时,我们都会向它添加一个新的 TableRow。这是我们在 UI 中看到的输出:

她走在美丽中,像
万里无云的星空和星空;
万里无云的地方和繁星点点的天空;
万里无云的地方和繁星点点的天空;
对那温柔的光
如此温柔 对那温柔的光芒如此温柔

然后我们进入调试器,看看为什么会这样。
有时synchronized (objectLock)会跳过并继续循环。
没有发布,因为i已经赶上了last
之后,该块被跳过的次数被执行
,但是原始行丢失并且当前行被添加到poem几次
然后,所有新行都被发布,直到再次i捕获last

所以你看到我遵循了代码,我可以解释发生了什么,这里的问题是:为什么跳过这个块?,为什么?
我预计同步块会停止,直到它可以被执行。
至少这是我如何理解synchronized (objectLock)
即使不使用wait()和的功能notify()

我不假装在这里打开一个讨论(虽然如果你想我们可以在聊天区打开一个)
如果你发现代码中有问题,那么,回答问题让我知道。

笔记:

  1. synchronized之所以需要,是因为在应用程序的其他地方,用户可能希望通过电子邮件发送他到目前为止收到的行。
  2. 用户可以暂停发布(bpause);这就是while循环,只有在错误时才会i遵循。lastbPause
4

2 回答 2

3

我决定公布答案。尽管我对它的简单感到很尴尬
我是在深入研究AsyncTask类和消息处理等之后才发现它的。

我发布它是希望它可以帮助人们在得出结论之前检查基本的东西,并且那里的人会因为这篇文章而节省半天的调试时间。

Record rec每次都是一样的。ArrayList 对每个条目都有相同的poem元素 id。并且所有的内容都立即改变了,因为它们都是一样的。
当进度立即发布时,它打印了正确的字符串,最后一个。但是,如果某些延迟导致进度稍后发布,则检索poem.get(i)记录会检索到不同的条目,但具有相同的指针,因此具有相同的内容。

解决方案是为每个循环创建一个新记录。

于 2012-05-20T17:03:11.187 回答
0

last对象进行同步。

synchronized (last) {
   last++;
   poem.add(last, line);
}
于 2012-05-20T05:43:18.150 回答