【问题标题】:Thread-safe NavigableSet with constant size-operation?具有恒定大小操作的线程安全 NavigableSet?
【发布时间】:2012-08-23 12:46:41
【问题描述】:

我正在寻找一个特定的数据结构,它与 ConcurrentSkipListSet 完全一样,但没有线性 size-操作,对于较大的集合可能会经常调用它。

我知道Collections.synchronizedNavigableSet(new TreeSet()),但是同步迭代:

synchronized (set) {
    Iterator<T> iter = set.iterator();
    while (iter.hasNext())
    iter.next();
}

很慢。

那么,您知道NavigableSet 实现与ConcurrentSkipListSet 完全相同,但没有线性size 操作,例如在Apache Commons、Guava 中?或者我应该对集合进行不同的迭代?

【问题讨论】:

  • 您也可以自己继承ConcurrentSkipListSet 并插入一小段代码来缓存和跟踪集合的大小。
  • 我已经想到了,也许我试试看,谢谢。我只是认为其他一些库可能会提供一个实现。
  • 再想一想,考虑到良好的并发性所施加的所有约束,实现它可能不值得。他们首先这样做是有充分理由的。
  • 你能减少多少你需要知道 size() 所以没关系?顺便说一句,当您调用此方法时,大小可能会发生变化,因此您只能知道大小,而不是大小。
  • 是的,大小不必那么准确(不需要阻塞整个数据结构),并且应该只反映调用时的“最佳猜测”。所以我开始使用一个保持当前大小的 volatile 实例变量来覆盖它,并让它在 add 返回时增加 true 并减少 删除类似。现在我尝试评估我所做的 - 如果它是明智的。

标签: java multithreading data-structures collections thread-safety


【解决方案1】:

他们没有以这种方式实施它是有充分理由的(即使用柜台)。 它是关于多处理器编程的语义。 并发程序有许多正确性模型,强(称为顺序一致性)和宽松(称为静态一致性)(参见 Maurice Herlihy 和 Nir ​​Shavit 的 The Art of Multiprocessor Programming 或 Quasi-Linearizability)。

计数器的实现未能遵守其中任何一个。 如果在实际添加和删除操作之前更新大小,它可能会变为负数(假设您在一个空集上删除和添加,删除首先更新大小导致 -1 大小......)。如果之后更新大小也是如此。 即使在添加操作之前增加大小并在删除之后减小大小的解决方案也有一个严重的缺点(但不会产生负值)。考虑两个使用参数“x”的添加操作和一个使用相同参数“x”的删除操作(都具有相同的元素)。可能存在大小将设置为 2 的情况(两次添加操作增加了计数器),一种从未存在的状态(集合从未有大小为 2,请注意我们总是添加相同的元素 'x' 和该集合不能包含重复项)。

它的实现方式(通过计算元素,具有线性时间复杂度)至少会产生一个在某个时间点存在的值(更准确地说,它是静态一致的)。

【讨论】:

    猜你喜欢
    • 2011-03-27
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-27
    • 2011-05-08
    • 2019-07-08
    相关资源
    最近更新 更多