You seem to understand the compromise well here, so I doubt that anyone can give you a final, principled answer. Fortunately, this is pretty simple to check.
I started by creating a simple Iterator<String> that has infinite paths over a finite list of randomly generated strings. (That is: during initialization, it generates an array of _strings random strings of length b from a pool of c different characters. The first call to next() returns _strings[0] , the next call returns _strings[1] & hellip; (n + 1) -th call returns _strings[0] again.) The rows returned by this iterator were what I used in all calls to SortedSet<String>.add(...) and SortedSet<String>remove(...) .
Then I wrote a test method that takes an empty SortedSet<String> and loop d times. At each iteration, it adds e elements, then deletes f elements, and then iterates over the entire set. (As a health check, it keeps track of the given size using the return values add() and remove() , and when iterating over the entire set, it ensures that it finds the expected number of elements. That thereโs just something in the body of the loop.)
I don't think I need to explain what my main(...) method does. main(...)
I tried different values โโfor different parameters, and I found that sometimes ConcurrentSkipListSet<String> performed better, and sometimes TreeSet<String> , but the difference was no more than doubled. In general, ConcurrentSkipListSet<String> better when:
- a, b and / or c were relatively large. (I mean, within the ranges that I tested. My range ranged from 1000 to 10000, my b from 3 to 10, my c from 10 to 80. In general, the resulting set sizes ranged from about 450 to about 10000, with modes 666 and 6666, because I usually used e = 2 & lrm; f.) This suggests that
ConcurrentSkipListSet<String> does a little better than TreeSet<String> with larger sets and / or with more expensive comparisons lines. Trying to use specific values โโdesigned to tease these two factors, I got the impression that ConcurrentSkipListSet<String> noticeably better than TreeSet<String> with larger sets, and slightly less good with more expensive string mappings. (This is basically what you expect; the TreeSet<String> binary tree approach aims at the absolute minimum possible number of comparisons.) - e and f were small; that is, when I called
add(...) and remove(...) only a small number of times per iteration. (This is exactly what you predicted.) The exact pivot point depended on a, b, and c, but as a first approximation ConcurrentSkipListSet<String> performed better when e + f was less than about 10, and TreeSet<String> performed better when e + f is greater than about 20.
Of course, it was on a machine that might look different than yours, using the JDK, which might look different from yours, and use very artificial data that might look different from yours. I would recommend you do your own tests. Since Tree* and ConcurrentSkipList* implement Sorted* , you can easily try your code in both directions and see what you find.
For what I know, ConcurrentSkipList * are basically CAS based locks, so they shouldn't carry overhead [& hellip;]
I understand that this will depend on the machine. On some systems, locking may not be possible, in which case these classes will have to use locks. (But since you are not really multithreaded, even locks may not be that expensive. Of course, there are overheads for synchronization, but its main cost is a lock conflict and forced single-threading. This is not a problem for you. Again, I think you just need to check and see how the two versions work.)