如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中进行了描述,因此该行为不会改变,因此您现在正在做的事情绝对没问题。它是使用泄漏抽象设计的,因此,如果您从头开始做类似的事情,则不应像这样设计,但是要记录泄漏抽象的属性。