4


挿入順序を維持しながら、(ConcurrentModificationExceptionをスローしないように)同時に変更できるSet実装が必要です。私は自分のコンパレータで

使用してみました-サンプルコード: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]を出力するため、このコンパレータは#failであるように見えます。bが2回そこにある場合、そのセットはありません。
私が見なければならない他の選択肢はありますか?

4

3 に答える 3

3

全順序プロパティに従わないコンパレータを定義しました。2つのオブジェクトの場合、一方が他方よりも小さいか、もう一方が最初のオブジェクトよりも小さい必要があります。

あなたの場合、オブジェクトが等しくない場合、それぞれが他よりも小さくなります。

ConcurrentSkipListSetコレクション内の要素のタイプを示すタイプパラメータなしでインスタンス化するため、キャストを使用しない限り、コンパレータを定義する際に問題が発生します。ただし、を作成するnew ConcurrentSkipListSet<String>と、オブジェクトが文字列であることがわかるため、コンパレータの定義が簡単になります。

于 2011-06-23T14:41:20.117 に答える
2

文字列の挿入順序を保持してそれを使用するコンパレータを定義できますが、それはきれいではありませんが、コンパレータは常に新しい要素ごとに呼び出されるため、次のようなことを行う必要があります。

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

ねえ、私はそれがきれいではないと言った...

于 2011-06-23T22:56:38.507 に答える
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 の懸念はまだ残っていると思います。

于 2011-06-24T07:29:10.233 に答える