【问题标题】:What Java Data Structure/Solution would best fit these requirements?哪种 Java 数据结构/解决方案最适合这些要求?
【发布时间】:2009-04-20 02:14:45
【问题描述】:

我需要一个满足这些要求的 java 数据结构/解决方案。什么最适合这些?

1) 必须保持对象的插入顺序

2) 对象必须是唯一的(这些是由 UUID 唯一标识的数据库对象)。

3) 如果添加了具有相同 ID 的较新对象,则应覆盖/删除旧版本的对象

4) 解决方案应该可以被多个线程访问。

5) 当第一个添加到结构中的对象被读取/使用时,它应该从数据结构中删除

【问题讨论】:

  • 对象是按顺序访问的吗?还是随机的?与 3) 您希望对象位置移动最近插入的对象吗?

标签: java data-structures collections concurrency


【解决方案1】:

这里有几种可能性。最简单的可能是从LinkedHashSet 开始。这将为您提供所需的唯一性和可预测的排序。然后,您可以包装结果集以使其成为线程安全的:

Set<T> s = Collections.synchronizedSet(new LinkedHashSet<T>(...));

注意:由于 Set 并没有真正定义从中检索项目的方法,因此您的代码必须手动调用 Set.remove(Object)。

或者,您可以包装一个LinkedHashMap,它确实为您需要的读取时删除语义提供了一个钩子:

class DeleteOnReadMap<K, V> implements Map<K, V> {

    private Map<K, V> m = new LinkedHashMap<K, V>();

    // implement Map "read" methods Map with delete-on-read semantics
    public V get(K key) {
        // ...
    }
    // (other read methods here)

    // implement remaining Map methods by forwarding to inner Map
    public V put(K key, V value) {
        return m.put(key, value);
    }
    // (remaining Map methods here)
}

最后,包装自定义 Map 的实例以使其成为线程安全的:

Map<K, V> m = Collections.synchronizedMap(new DeleteOnReadMap<K, V>(...));

【讨论】:

  • 为了使其线程安全——你可以这样做 Set s = Collections.synchronizedSet(new LinkedHashSet(...));
  • 为了使其线程安全,delete-on-read 语义必须在同步代码中,否则两次读取可能会暴露竞争条件。
  • @Peter 好点,但是,我刚刚意识到 Set 没有等效的 get() - 所以无论如何删除都必须在 Set 外部发生。我在我的答案中添加了一个更有用的地图示例。如果客户端仍然通过某个 UUID 引用对象,可能更有意义。
【解决方案2】:

我的想法是这样的:

 Collections.synchronizedMap(new LinkedHashMap<K, V>());

我认为这可以解决除要求 5 之外的所有问题,但您可以使用 remove() 方法而不是 get() 来做到这一点。

这不会像ConcurrentMap 那样高效 - 同步在每次访问时锁定整个映射,但我认为 ConncurrentMap 实现可以仅在映射的一部分上使用读写锁和选择性锁定允许多个非冲突访问同时进行。如果您愿意,您可能可以通过编写自己的某些现有 Map 实现的子类来获得更好的性能。

【讨论】:

    【解决方案3】:

    1) 对象的插入顺序必须是 保留

    这是任何“正常”的数据结构——数组、数组列表、树。因此,请避免自平衡或自排序数据结构:堆、哈希表或移至前端树(例如,展开树)。再说一次,您可以使用其中一种结构,但是那么你必须跟踪它在每个节点中的插入顺序。

    2) 对象必须是唯一的(这些是 唯一的数据库对象 由 UUID 标识)。

    为每个对象保留一个唯一标识符。如果这是一个 C 程序,那么指向该节点的指针是唯一的(我想这也适用于 Java。)如果节点的指针不足以保持“唯一性”,那么您需要向每个节点添加一个字段你保证有一个独特的价值。

    3) 如果具有相同 ID 的较新对象 添加,旧版本的 对象应该被覆盖/删除

    你想把节点放在哪里?您要替换现有节点吗?还是要删除旧节点,然后在末尾添加新节点?这很重要,因为它与您的要求 #1 相关,其中必须保留插入顺序。

    4) 解决方案应该是可访问的 许多线程。

    我能想到的唯一方法是实现某种锁定。 Java 允许您将结构和代码包装在 synchronized 块中。

    5) 当第一个对象添加到 结构被读取/使用,它应该是 从数据结构中删除

    有点像“出队”操作。

    似乎 ArrayList 是一个很好的选择:仅仅因为#5。唯一的问题是搜索是线性的。但是,如果您的数据量相对较少,那么问题就不是那么大了。

    否则,就像其他人所说的那样:HashMap 甚至某种树都可以工作 - 但这取决于访问的频率。 (例如,如果“最近”元素最有可能被访问,我会使用线性结构。但如果访问是“随机”元素,我会使用 HashMap 或 Tree。)

    【讨论】:

      【解决方案4】:

      关于 LinkedHashSet 的解决方案将是一个很好的起点。

      但是,您必须覆盖要放入集合中的对象的 equals 和 hashcode 方法以满足您的要求 3。

      【讨论】:

        【解决方案5】:

        听起来您必须创建自己的数据结构,但这听起来很简单。

        基本上,您可以从数组或堆栈之类的任何东西开始,但随后您必须为其余功能扩展它。

        您可以根据需要查看“包含”方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-17
          • 1970-01-01
          • 2010-11-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多