Java_author所述,



下面代码中的对象X是list。以上说明,使用ListHelper类型对象拥有的锁来同步putIfAbsent(),是错误的锁。

package compositeobjects;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ListHelper<E> {

    private List<E> list =
                    Collections.synchronizedList(new ArrayList<E>());


    public boolean putIfAbsent(E x) {
        synchronized(list){
            boolean absent = !list.contains(x);
            if(absent) {
                list.add(x);
            }
            return absent;
        }
    }
}

但是,Java作者说,



我的理解是,Collections.synchronizedList()返回的嵌套类实例也使用了list对象拥有的锁。

为什么在list中使用客户端锁定(带有ListHelper)违反了同步策略的封装?

最佳答案

您所依赖的事实是synchronizedList将自身用作监视程序,目前恰好是事实。

您甚至依赖于synchronizedList使用synchronized来实现同步这一事实,目前这也确实是正确的(这是一个合理的假设,但不是必须的)。

可以通过多种方式更改synchronizedList的实现,以使您的代码无法正常工作。

例如,the constructor of synchronizedList :

SynchronizedList(List<E> list) {
  super(list);
  // ...
}

可以更改为
SynchronizedList(List<E> list) {
  super(list, new Object());
  // ...
}

现在,mutex实现中的方法所使用的SynchronizedList字段不再有效(不再有效)为this,因此在list上进行外部同步将不再起作用。

话虽如此,使用synchronized (list)确实具有预期的效果已在Javadoc中进行了描述,因此该行为不会改变,因此您现在正在做的事情绝对没问题。它是使用泄漏抽象设计的,因此,如果您从头开始做类似的事情,则不应像这样设计,但是要记录泄漏抽象的属性。

10-06 10:52