0

I am having an issue with a simplistic thread-safe implementation of the observer pattern using a ConcurrentSkipListSet to handle keeping track of observer priorities during insertion. The majority of observers will not have any special priority attributed to them, and following this Comparable#compareTo method will show as equal priority when compared (where priority is a value in an enum of five priorities ranging from highest to lowest):

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

When I add observers of equal priorities to the ConcurrentSkipListSet , it seems like some of the added objects are simply lost during the insertion process. Changing the priorities of any of the observers I have created while testing this results in those observers being added to the set without issue, though I assume that given enough observers of the same priority the issue will arise again.

I am unsure about what is causing this issue, and of what I should do to help resolve it. Is there anything I can do to resolve this issue? Alternatively if this is an inherent problem with the ConcurrentSkipListSet, are there any other thread-safe data structures that can give me reasonably performant insertion and sorting times for unique objects?

Mark J
  • 20
  • 3
  • Two hints: In a `Set`, special things happen to elements that are equal. The meaning of `0` as return value of `compareTo` has a special meaning too. – zapl May 18 '16 at 22:25

1 Answers1

0

I presume that you are instantiating like this ConcurrentSkipListSet(myComparator) where myComparator implements compareTo as you have shown us.

A ConcurrentSkipListSet is a Set. When you instantiate one using a Comparator, it will use it to:

  1. order the set elements
  2. determine when a new element is already in the set.

In your code, your Comparator.compareTo(...) is saying that every BaseLink with a given priority is the same. That's what is causing your problem.

Solution:

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;
}

If your BaseLink objects have a natural key or identifier, you could use that as the tie-breaker for objects with the same priority. Even the object's identity hashcode would do ... if you are not worried about "fairness" or "reproducibility" in the ordering of the set.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • And, if all else fails to differentiate the BaseLInks, you can force a difference by comparing their `System.identityHashCode().` – user949300 May 18 '16 at 23:48
  • This helped me solve my problem, thank you very much for taking the time to answer. Introducing a discriminant worked perfectly! – Mark J May 19 '16 at 00:23