Java 如何构造非重复列表?

Java 如何构造非重复列表?,java,thread-safety,Java,Thread Safety,我想用下面的代码构造一个不重复的列表,但有些地方出错了,有人说它是线程不安全的,但我不明白,所以请给我一些例子来证明它,谢谢 class BadListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public synchronized boolean putIfAbsent(E x) { bo

我想用下面的代码构造一个不重复的列表,但有些地方出错了,有人说它是线程不安全的,但我不明白,所以请给我一些例子来证明它,谢谢

class BadListHelper <E> {  
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());  
    public synchronized boolean putIfAbsent(E x) {  
        boolean absent = !list.contains(x);  
        if (absent)  
            list.add(x);  
        return absent;  
    }  
} 
类BadListHelper{
public List=Collections.synchronizedList(新的ArrayList());
公共同步布尔putIfAbsent(ex){
布尔缺席=!list.contains(x);
如果(缺席)
增加(x);
缺席返回;
}  
} 

代码的一个问题是(公开的)
列表
对象上的操作和
putIfAbsent
方法在不同的对象上同步。这意味着
putIfAbsent
对于
list
上的直接操作具有竞争条件

例如,如果您有两个线程:

  • 线程A调用helper.list.add(e)
  • 线程B调用helper.putIfAbsent(e)
然后你可能会在列表中出现两次
e
。。。视时间而定

public synchronized boolean putIfAbsent(E x) {  
    boolean absent = !list.contains(x);  
    // <<--- the Thread A call could happen here.
    if (absent)  {
        list.add(x);  
    }
    return absent;  
}

什么是“非重复列表”?什么是“不对劲”?预期和实际行为是什么?为什么不使用
集合
?更具体地说是一个
LinkedHashSet
(如果您想保持插入顺序)?@anacron它必须类似于
LinkedHashSet
,以确保顺序。我只是不明白问题出在哪里,很抱歉,我没有表达我自己clearly@OldCurmudgeon-这是不安全的。。。请参阅我的答案以了解解释谢谢我的朋友,但是“public synchronized boolean putIfAbsent(ex)”意味着在当前方法完成之前,另一个线程无法调用此方法,因此为什么会出现多线程问题呢?
synchronized
方法调用只排除在
this
上同步的其他方法调用。这是与
列表
不同的对象。因此,不排除
列表中的方法调用
public boolean putIfAbsent(E x) {  
    synchronized (list) {
        boolean absent = !list.contains(x);  
        if (absent) { 
            list.add(x);  
        }
        return absent;
    }
}