Java 具有恒定大小操作的线程安全NavigableSet?
我正在搜索一个特定的数据结构,它与Java 具有恒定大小操作的线程安全NavigableSet?,java,multithreading,data-structures,collections,thread-safety,Java,Multithreading,Data Structures,Collections,Thread Safety,我正在搜索一个特定的数据结构,它与ConcurrentSkipListSet完全相似,但没有线性size-操作,对于较大的集合,可能会经常调用该操作 我知道集合。synchronizedNavigableSet(new TreeSet()),但同步迭代: synchronized (set) { Iterator<T> iter = set.iterator(); while (iter.hasNext()) iter.next(); } 已同步(设置){
ConcurrentSkipListSet
完全相似,但没有线性size
-操作,对于较大的集合,可能会经常调用该操作
我知道集合。synchronizedNavigableSet(new TreeSet()),但同步迭代:
synchronized (set) {
Iterator<T> iter = set.iterator();
while (iter.hasNext())
iter.next();
}
已同步(设置){
迭代器iter=set.Iterator();
while(iter.hasNext())
iter.next();
}
速度相当慢
那么,您是否知道
NavigableSet
实现完全类似于ConcurrentSkipListSet
,但没有线性size
操作,例如在Apache Commons、Guava中?或者我应该在集合上进行不同的迭代吗?有一个很好的理由说明为什么他们没有以这种方式实现它(即使用计数器)。
它是关于多处理器编程的语义。
并发程序的正确性模型有很多,强一致性称为顺序一致性,松弛一致性称为静态一致性(参见Maurice Herlihy和Nir Shavit的《多处理器编程艺术》)
带有计数器的实现无法遵守其中任何一项。
如果在实际的添加和删除操作之前更新了大小,则大小可能会变为负值(假设您在一个空集上进行了删除和添加,则删除首先更新了大小,结果是-1大小…)。如果随后更新了大小,则情况也是如此。
即使是在添加操作之前增大大小并在移除之后减小大小的解决方案也有严重的缺点(但是不会产生负值)。考虑两个带有参数x的加法运算和一个具有相同参数x的删除(所有元素都是相同的)。可能存在这样一种情况,即大小将设置为2(两次添加操作增加了计数器),这是一种从未存在过的状态(该集的大小从未为2,请注意,我们始终添加相同的元素“x”,并且该集不能包含重复项)
它的实现方式(通过计算元素,具有线性时间复杂性)将至少产生一个在某个时间点存在的值(更准确地说,它是静态一致的).您也可以自己对
ConcurrentSkipListSet
进行子类化,插入一点代码来缓存和跟踪集合的大小。我已经想到了,也许我可以试试,谢谢。我只是认为其他库可能会提供一个实现。再想想,考虑到良好的并发性带来的所有约束,实现它可能不值得。一开始他们这样做有一个很好的理由。你能减少多少你需要知道的大小()这样就不重要了吗?顺便说一句,在调用此方法时,大小可能会发生变化,因此您只能知道大小是什么,而不是它是什么。是的,大小不必那么精确(无需阻塞整个数据结构),只应反映调用时的“最佳猜测”。因此,我开始使用一个保持当前大小的volatile
实例变量覆盖它,并在add
返回true
时使其递增,在remove
类似时使其递减。现在我试着评估我所做的事情——如果它是合理的话。