我使用的是ConcurrentSkipListSet,显然是通过多个线程访问的。现在,底层对象的compareTo方法使用的值会随时间发生变化。因此,我想“更新”列表的顺序(通过使用它或类似的东西)。
然而,java.util.Collections.sort(list)不起作用,只是重建列表可能太慢了(并且会破坏整个并发性)。我应该看看还有其他解决方案吗?
它不必导致最佳排序(无论如何,并发和更改值几乎不可能)。只要任何删除/添加调用保持线程证明(在排序时重建列表时这将是一个真正的问题),接近最佳就足够了。
答案 0 :(得分:7)
每当您编辑项目以使其排序顺序可能发生变化时,您必须将其从列表中删除,然后更改密钥,然后重新插入。
Cliff博士点击Azul Systems有very nice presentation他们如何使用墓碑等进行无锁哈希表。如果你开始编写自己的跳过列表/树来将项目重新排序为单个 - 并且希望更快 - 那么你也可以使用这种无锁路由。并确保分享您的结果:)
答案 1 :(得分:2)
Java API中的这些类型的集合不支持可变元素(即compareTo方法更改的元素)。因此,唯一的方法是以原子方式重新组装新列表,或者Will建议您可以执行元素的删除,变异和重新插入。
HashSet有同样的问题 - 在插入对象时计算哈希桶,如果你改变了对象的哈希码,你将无法做set.contains( ... )
。
确切地说,ConcurrentSkipListSet和HashSet之类的集合在插入和删除时执行它们的比较/散列。唯一支持'可变元素不会根据元素的状态(例如ArrayList)执行特殊的插入逻辑。
Set接口的documentation说明:
注意:如果将可变对象用作set元素,则必须非常小心。如果在对象是集合中的元素的同时以影响等于比较的方式更改对象的值,则不指定集合的行为。这种禁止的一个特例是,不允许集合将自己作为一个元素包含在内。
和SortedSet接口的documentation说明:
请注意,如果有序集合要正确实现Set接口,则由有序集合维护的排序(无论是否提供显式比较器)必须与equals一致。 (有关与equals一致的精确定义,请参阅Comparable接口或Comparator接口。)这是因为Set接口是根据equals操作定义的,但是有序集使用compareTo(或compare)方法执行所有元素比较因此,从排序集的角度来看,这种方法被认为相等的两个元素是相等的。即使排序与equals不一致,排序集的行为也是明确定义的;它只是没有遵守Set接口的一般合同。