2

我不确定是否有问题java.util.concurrent.ConcurrentSkipListSet?我正在尝试将一些对象添加到 ConcurrentSkipListSet (由我自己的比较器维护的顺序)。添加后,我改变了一些对象的状态。我更改的属性包括比较器中使用的属性。现在,当我尝试删除一些对象时,它失败了。该对象不会从 ConcurrentSkipListSet 中删除,并且remove(Object)返回 false。

如果我用 TreeSet 替换 ConcurrentSkipListSet 我看不到这种行为。

不确定我是否在这里做一些愚蠢的事情或遗漏了什么:(。这是一个示例代码片段。

public class TreeVsSkip {
static TreeSet ts = new TreeSet(new Comparator(){

    @Override
    public int compare(Object o1, Object o2) {
        if(((Emp)o1).empid == ((Emp)o2).empid){
            return 0;
        }
        if(((Emp)o1).empid > ((Emp)o2).empid){
            return 1;
        }
        return -1;
    }

});

static ConcurrentSkipListSet<Emp> csls = new ConcurrentSkipListSet(new Comparator(){

    @Override
    public int compare(Object o1, Object o2) {
        if(((Emp)o1).empid == ((Emp)o2).empid){
            return 0;
        }
        if(((Emp)o1).empid > ((Emp)o2).empid){
            return 1;
        }
        return -1;
    }

});
public static void main(String ...strings ){
    System.out.println("Testing Tree...");
    Emp e1 = new Emp(1,"abc");

    ts.add(e1);
    ts.add(new Emp(2,"pqr"));
    ts.add(new Emp(3,"xyz"));
    System.out.println(ts);
    e1.setName("test");
    e1.setId(8);
    System.out.println(ts);
    ts.remove(new Emp(3,"xyz"));
    System.out.println(ts);


    System.out.println("Testing ConcurrentSkipSet...");
    e1.setName("abc");
    e1.setId(1);
    csls.add(e1);
    csls.add(new Emp(2,"pqr"));
    csls.add(new Emp(3,"xyz"));
    System.out.println(csls);
    e1.setName("test");
    e1.setId(8);
    System.out.println(csls);
    System.out.println(csls.remove(new Emp(3,"xyz")));
    System.out.println(csls);
}

static class Emp {
    int empid;
    String name;
    Emp(int id, String n){
        empid = id;
        name = n;
    }
    void setName(String pname){
        name = pname;
    }
    void setId(int pID){
        empid = pID;
    }
    public String toString(){
        return "EmpId:"+empid+"Name:"+name;
    }
}

}

输出如下所示:

Testing Tree...
[EmpId:1Name:abc, EmpId:2Name:pqr, EmpId:3Name:xyz]
[EmpId:8Name:test, EmpId:2Name:pqr, EmpId:3Name:xyz]
[EmpId:8Name:test, EmpId:2Name:pqr]
Testing ConcurrentSkipSet...
[EmpId:1Name:abc, EmpId:2Name:pqr, EmpId:3Name:xyz]
[EmpId:8Name:test, EmpId:2Name:pqr, EmpId:3Name:xyz]
false
[EmpId:8Name:test, EmpId:2Name:pqr, EmpId:3Name:xyz]

请注意,此行为并不一致。有时元素会被删除。

我在 OS X 版本 10.11.6 上使用 java 版本“1.8.0_131”。

为破旧的代码道歉。赶紧煮好了。

谢谢。

4

1 回答 1

3

当您将项目添加到集合或用作地图中的键时,您不能更改任何用于比较的字段,例如 compareTo 或 Comparator 或 hashCode/equals (视情况而定),或者您已损坏集合。

删除此类项目的唯一方法是遍历所有元素并通过迭代器将其删除。

顺便说一句,我会避免使用静态集合,但如果你必须这样做

static final Set<Emp> csls = new ConcurrentSkipListSet(
                                            Comparator.comparing(e -> e.empid));

如果要更改,则empid需要先将其删除,然后对其进行更改,然后再将其重新添加。为了避免由辅助人员执行此操作,我将final仅在构造函数中设置该字段。

于 2017-05-17T13:32:38.947 回答