2

我有一个非粘性服务,它通过广播接收器定期调用,以启动一个执行某些任务的线程。当线程正在运行时,正在进行的通知会显示一些进度信息,以及用于调出状态页面的按钮。

此状态页面显示当前正在处理的项目列表,此列表是线程和此活动都使用的静态 ArrayList。当状态活动开始时,我有一个空检查:

if(Global.statusItems == null)
{
    Global.statusItems = new ArrayList<StatusPageItem>();
}

线程仍在运行,并且可以很好地访问 ArrayList,但是一旦启动 Status Activity,它将重新创建 ArrayList,就好像它为空一样。

到目前为止,如果不使用 ObjectOutputStream 保存列表并在状态页面启动时重新加载,我无法解决问题。我可以使用更优雅的解决方案吗?

问候,昆特。

4

2 回答 2

1

您需要确保 2 行代码(空测试和新列表的创建)是原子的,并且分配对其他线程可见。

最简单的方法是同步那段代码:

synchronized(Global.class) {
    if(Global.statusItems == null) {
        Global.statusItems = new ArrayList<StatusPageItem>();
    }
}

但是,如果您需要从一个线程读取列表并从另一个线程写入,则需要在添加/删除/迭代时添加额外的同步,以确保两个线程看到相同的列表 - 如果您不这样做,写入线程可能会将一个项目添加到列表中,但读取线程看不到它。

最简单的方法是使用 list 的线程安全实现:

synchronized(Global.class) {
    if(Global.statusItems == null) {
        Global.statusItems = new CopyOnWriteArrayList<StatusPageItem>();
    }
}

如果内存/对象创建是一个问题(从这个角度来看,CopyOnWriteArrayList 不是很有效),您也可以使用同步集合来代替:

synchronized(Global.class) {
    if(Global.statusItems == null) {
        Global.statusItems = Collections.synchronizedList(new ArrayList<StatusPageItem>());
    }
}

在这种情况下,请确保在迭代时锁定集合:

synchronized(Global.statusItems) {
    for (StatusPageItem item : Global.statusItems) {

    }
}
于 2012-08-29T11:04:21.953 回答
1

您的服务是否有可能在不同的进程上运行?

于 2012-08-29T11:12:51.387 回答