我在实现一种线程安全的方式来集中更新和访问我的 Android 应用程序中的类对象列表时遇到了一些麻烦。这是一个开放式问题,无法提供很多源代码。
基本上我有一个带有活动和服务的应用程序。Service实现了UDP广播任务和UDP广播监听任务。广播的信息本质上是代表设备的类的 JSON 序列化副本。例如 UUID、IP、一些管理信息,如用户设置名称、描述等... JSON 存储在 UDP 数据包中并发送,UDP 数据包被接收并反序列化和处理。该反序列化的类存储在 Hashtable 中,当前实例属于服务。例如,每个想要访问数据的人都必须通过服务。整个事情是非常异步的。
Activity 绑定到服务(通过和扩展 Binder),因此它可以调用服务方法,例如启动/停止 UDP 任务。当收到任何更新或新设备数据时,Activity 将侦听 Service 将发出的 Android Intent,并且 UI 将显示与接收到的 UDP 数据包数据相关的信息。再次注意,数据包数据存储在属于服务的容器类中。
问题是我想不出一种合适的方法来使接收数据线程的哈希表安全。当从 Service 方法获取数据并进行处理时,我得到 java.util.ConcurrentModificationException 错误。如果在循环(迭代器或 for)中处理数据时更新了数据,则会发生 ConcurrentModificationException。我知道在哪里、何时以及为什么,但使用 lock() 或 ReentrantLock() 通常在具有要锁定数据的类的方法调用中使用,而不是在返回以在该容器类之外进行处理的单点数据上使用。类似的东西:(我使用的是同步,而不是 ReentrantLock(),它只是一个例子)
public class sampleLockClass {
private Hashtable<String, String> sampleData = new Hashtable<String, String>();
public sampleLockClass() {}
public synchronized put(String s1, String s2) {
this.sampleData().put(s1, s2);
}
public synchronized Hashtable<String, String> getAll() {
return this.sampleData; // This is returned for the processing outside the class
}
}
在这种情况下,getAll() 方法返回 sampleData Hashtable,因为它需要在类本身之外进行处理。这样做的原因是数据被传递到我正在利用的其他 API,并且它们与这种方法不兼容。例如,他们希望有一个单一的、线程安全的副本供其使用。
也许这是一个愚蠢或非问题,但是您将如何使返回的 sampleData 线程在其需要的期间安全?请注意,目前只有服务会写入 sampleData。其他所有内容都是只读的,我可能会尝试通过 Intent 通过 CommService 从 Activity 提交对 sampleData 的任何更新。
尝试为每个 get() 方法复制 Hashtable sampleData 会更安全吗?