Проблема с ConcurrentSkipListSet remove()
Я не уверен, есть ли проблема с java.util.concurrent.ConcurrentSkipListSet
? Я пытаюсь добавить некоторые объекты в ConcurrentSkipListSet (порядок поддерживается моим собственным компаратором). После добавления я изменяю состояние некоторых объектов. Свойства, которые я изменяю, включают те, которые используются в компараторе. Теперь, когда я пытаюсь удалить некоторые объекты, происходит сбой. Объект не удаляется из ConcurrentSkipListSet и remove(Object)
возвращает ложь
Если я заменю ConcurrentSkipListSet на TreeSet, я не вижу этого поведения.
Не уверен, что я делаю что-то действительно глупое или что-то упустил:(. Вот пример кода.
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]
Обратите внимание, что это поведение не соответствует. Иногда элемент удаляется.
Я использую версию Java "1.8.0_131" на OS X версии 10.11.6.
Извиняюсь за потертый код. Приготовил это в спешке.
Благодарю.
1 ответ
Когда вы добавляете элемент в набор или используете его в качестве ключа на карте, вы не можете изменить любое поле, которое используется для сравнения, например, CompareTo или Comparator или hashCode / equals, в зависимости от ситуации, или вы испортили коллекцию.
Единственный способ удалить такие элементы - это перебрать все элементы и удалить их через итератор.
Кстати, я бы не использовал статическую коллекцию, но если вам нужно, вы можете сделать
static final Set<Emp> csls = new ConcurrentSkipListSet(
Comparator.comparing(e -> e.empid));
Если вы собираетесь изменить empid
вам нужно будет сначала удалить его, изменить его, а затем добавить обратно. Чтобы избежать этого с помощью acdient, я бы сделал поле final
установка его только в конструкторе.