如何实现维护插入顺序的并发集合




我需要一个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);
    }

但这个比较器似乎是一个#失败,因为集合打印:
[b,c,a,b,d]。如果b在那里两次,那就不确定了
我还有其他选择吗?

您定义了一个不遵守total order属性的比较器。对于两个对象,其中一个应该比另一个小,或者另一个比第一个小。

在您的情况下,如果对象不相等,则每个对象都比另一个小。

由于实例化ConcurrentSkipListSet时没有任何类型参数来说明集合中元素的类型,因此除非使用强制转换,否则在定义比较器时会遇到问题。但是,如果您创建了一个new ConcurrentSkipListSet<String>,那么定义比较器将更容易,因为您将知道您的对象是字符串。

您可以定义一个比较器,它将保持字符串的插入顺序并使用它,这不会很漂亮,但由于比较器总是为每个新元素调用,所以您需要做的就是这样的事情:

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[]{}));
}

嘿,我说不好看。。。

我几乎使用了@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对种族状况的担忧仍然存在。

相关内容

  • 没有找到相关文章

最新更新