我需要一个Set实现,它将让我保持插入顺序并且仍然可以进行可修改(如不抛出ConcurrentModificationException)。
我尝试使用ConcurrentSkipListSet
和我自己的比较器 - 示例代码:
public static void main(String[] str){
ConcurrentSkipListSet set = new ConcurrentSkipListSet(new Comparator() {
public int compare(Object o1, Object o2) {
if(o1.equals(o2)){
return 0;
}
return -1;
}
});
set.add("d");
set.add("b");
set.add("a");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
set.add("c");
set.add("b");
System.out.println(set);
set.remove("b");
System.out.println(set);
}
但看起来这个比较器是#fail,因为该组打印:
[b,c,a,b,d]。如果b在那里两次没有设定。
我应该看看还有其他选择吗?
答案 0 :(得分:3)
您已经定义了一个不遵守total order property的比较器。对于两个对象,要么一个小于另一个,要么小于第一个。
在您的情况下,如果对象不相等,则每个对象都小于另一个。
由于您在没有任何类型参数的情况下实例化ConcurrentSkipListSet
,说明集合中元素的类型是什么,除非您使用强制转换,否则您将无法定义比较器。但是如果你创建一个new ConcurrentSkipListSet<String>
,那么定义比较器会更容易,因为你会知道你的对象是字符串。
答案 1 :(得分:1)
你可以定义一个比较器,它将保持字符串的插入顺序并使用它,它不会很漂亮,但由于总是为每个新元素调用比较器所有你需要做的就是这样:
public void testInsertionOrderSkipListSet() {
Comparator<String> insertionOrderComparator = new Comparator<String>() {
private final ConcurrentHashMap<String, Integer> order = new ConcurrentHashMap<String, Integer>();
@Override
public int compare(String o1, String o2) {
if (!order.contains(o2)) //only happens on second insert
order.put(o2, 0);
if (order.containsKey(o1))
return order.get(o1).compareTo(order.get(o2));
order.put(o1, order.size());
return 1;
}
};
ConcurrentSkipListSet<String> set = new ConcurrentSkipListSet<String>(insertionOrderComparator);
set.add("a");
set.add("c");
set.add("e");
set.add("b");
set.add("d");
set.add("c");
assertArrayEquals(new String[] { "a", "c", "e", "b", "d"}, set.toArray(new String[]{}));
}
嘿,我说它不漂亮......
答案 2 :(得分:0)
我几乎使用了@Asaf的解决方案,不过我对删除操作也做了一点改进:
class ConcurrentInsertionOrderSet extends ConcurrentSkipListSet{
Map<Object, Integer> orderMap;
final AtomicInteger increment = new AtomicInteger();
public ConcurrentInsertionOrderSet(final Map<Object, Integer> orderMap) {
super(new Comparator<Object>() {
public int compare(Object o1, Object o2) {
return (orderMap.get(o1).compareTo(orderMap.get(o2)));
}
});
this.orderMap = orderMap;
}
@Override
public boolean add(Object o) {
if (!orderMap.containsKey(o))
orderMap.put(o, increment.incrementAndGet());
return super.add(o);
}
@Override
public boolean remove(Object o) {
boolean b = super.remove(o);
if(b)
orderMap.remove(o);
return b;
}
}
对于测试:
public static void main(String[] str){
ConcurrentSkipListSet set = new ConcurrentInsertionOrderSet(new ConcurrentHashMap());
set.add("d");
set.add("b");
set.add("a");
set.add("c");
set.add("b");
set.add("c");
set.add("g");
System.out.println(set);
set.remove("b");
System.out.println(set);
set.remove("c");
set.add("c");
System.out.println(set);
}
输出很好且一致:
[d,b,a,c,g]
[d,a,c,g]
[d,a,g,c]
但我猜@ axel22对种族状况的担忧仍然存在。