如何实现一个可以在没有并发异常的情况下访问的线程安全中心对象/列表?

时间:2013-07-17 16:17:21

标签: android thread-safety locking android-service

我在实现一种线程安全的方式来集中更新和访问我的Android应用程序中的类对象列表时遇到了一些麻烦。这是一个开放式的问题,不能给出很多源代码。

基本上我有一个带有活动和服务的应用程序。该服务实现UDP广播任务和UDP广播监听任务。广播的信息本质上是表示设备的类的JSON序列化副本。例如UUID,IP,一些管理信息,如用户集名称,描述等...... JSON存储在UDP数据包中并发送,UDP数据包被接收和反序列化并处理。该反序列化类存储在Hashtable中,当前实例属于服务。例如每个想要访问数据的人都必须通过该服务。整件事情非常异常。

活动绑定到服务(通过和扩展Binder),因此它可以调用服务方法,如启动/停止UDP任务。当接收到任何更新或新设备数据时,Activity将侦听服务将发出的Android Intents,并且UI将显示与接收的UDP分组数据相关的信息。再次注意,分组数据存储在属于服务的容器类中。

问题是我无法找到一种合适的方法来使接收数据线程的Hashtable安全。从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的副本会更安全吗?

1 个答案:

答案 0 :(得分:0)

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html

  

支持检索的完全并发和可调整的哈希表   预期的更新并发性。本课程遵循相同的功能   规范为Hashtable,包括方法版本   对应于Hashtable的每种方法。

     

检索操作(包括get)一般不会阻塞,所以可能   与更新操作重叠(包括put和remove)。检索   反映最近完成的更新操作的结果   坚持他们的发作。对于诸如putAll和。之类的聚合操作   清除,并发检索可能仅反映插入或删除   一些条目。

     

更新操作之间允许的并发性由   可选的concurrencyLevel构造函数参数(默认为16),即   用作内部尺寸的提示。该表是内部的   分区以尝试允许指示的并发数   没有争用的更新。因为哈希表中的位置是   基本上是随机的,实际的并发性会有所不同。

     

公开集合值()

     

返回此地图中包含的值的Collection视图。该系列得到了支持   通过地图,对地图的更改将反映在集合中,反之亦然。   该集合支持元素删除,删除   来自此地图的相应映射,通过Iterator.remove,   Collection.remove,removeAll,retainAll和clear操作。确实如此   不支持add或addAll操作。视图的迭代器是一个   “弱一致”的迭代器永远不会抛出    ConcurrentModificationException ,并保证在构造迭代器时遍历元素,并且可能   (但不保证)反映之后的任何修改   构造