无法将相同优先级的对象插入ConcurrentSkipListSet

时间:2016-05-18 21:56:13

标签: java multithreading sorting comparator observer-pattern

我遇到了一个问题,即使用ConcurrentSkipListSet来简化线程安全的观察者模式实现,以便在插入过程中跟踪观察者的优先级。大多数观察者都没有任何特殊的优先权归属于他们,并且遵循此Comparable#compareTo方法在比较时将显示相同的优先级(其中 priority 是五个优先级的枚举值,范围从最高到最低):

public int compareTo(BaseLink<?> link) {
    return this.priority.compareTo(link.getPriority());
}

当我向ConcurrentSkipListSet添加具有相同优先级的观察者时,似乎在插入过程中会丢失一些添加的对象。更改我在测试时创建的任何观察者的优先级会导致这些观察者被添加到集合中而没有问题,但我认为如果给予相同优先级的足够观察者,问题将再次出现。

我不确定导致此问题的原因,以及我应该采取哪些措施来帮助解决此问题。有什么办法可以解决这个问题吗?或者,如果这是ConcurrentSkipListSet的固有问题,是否有任何其他线程安全的数据结构可以为独特对象提供合理的高效插入和排序时间?

1 个答案:

答案 0 :(得分:0)

我假设您正在实例化ConcurrentSkipListSet(myComparator),其中myComparator实现compareTo正如您向我们展示的那样。

ConcurrentSkipListSetSet。当您使用Comparator实例化一个时,它将使用它来:

  1. 订购设置元素
  2. 确定新元素何时已在集合中。
  3. 在您的代码中,您的Comparator.compareTo(...) 具有给定优先级的每个BaseLink都是相同的。这就是造成问题的原因。

    解决方案:

    public int compareTo(BaseLink<?> link) {
        int res = this.priority.compareTo(link.getPriority());
        if (res == 0) {
            // tie-breaker for different links with the same priority
            res = // compare using some other key / identifier
        }
        return res;
    }
    

    如果您的BaseLink对象具有自然键或标识符,则可以将其用作具有相同优先级的对象的平局。即使是对象的标识哈希码也可以...如果你不担心集合的顺序中的“公平性”或“可重复性”。