我想在两个对象之间实现一个简单的比较器,其唯一要求是
- 它是一个有效的比较器(即定义所有对象的线性顺序)和
.compare
当且仅当对象相同时才会返回 0 。
会Comparator.comparing(System::identityHashCode)
工作吗?还有其他方法吗?
动机: 我想构建一个集合,允许我将带时间戳的消息存储在线程安全集合中,该集合将支持诸如“获取时间戳位于 [a,b) 中的所有消息”之类的查询。
似乎番石榴TreeMultimap
使用了全局锁(编辑:如果用synchronizedSortedSetMultimap
包装器包装),并且ConcurrentSkipListMap
似乎每次只支持一个条目(它是一个映射,而不是一个多映射)。所以我想只使用一组对:
ConcurrentSkipListSet<ImmutablePair<Float,Message>> db
,
其中对是按词法排序的,首先是时间(使用Float.compareTo
),然后是类似的东西Comparator.nullsFirst(Comparator.comparing(System::identityHashCode))
。
nullsFirst
就是这样db.subSet(ImmutablePair.of(a,null), ImmutablePair.of(b,null))
查询半开时间间隔[a,b)。你明白为什么我关心比较器保持相同性:如果消息比较器为不同的消息返回零,则可能会删除消息。
你也明白了为什么我不需要比较器的其他东西:它就在那里,所以我可以使用
ConcurrentSkipListSet
. 我当然不想强加给用户(好吧,只是我 :-) 为Message
.另一种可能的解决方案是使用
ConcurrentSkipListMap<Float, Set<Message>>
(带有线程安全的 Set<> 实例),但在内存方面似乎有点浪费,一旦删除消息,我将需要自己删除 emptySet 以节省内存。
编辑:正如几个人所指出的,identityHashCode 可能会产生冲突,事实上我现在已经确认我的设置中存在这种冲突(这大致相当于上面有 4K 集合,每个集合每个时间箱都填充 4K 消息)。这很可能是我看到一些消息被丢弃的原因。所以我现在比以往任何时候都更有兴趣找到某种方式来拥有一个真正尊重相同性的“不可知”比较运算符。实际上,一个 64 位哈希值(而不是 identityHashCode 提供的 32 位值)可能就足够了。