以下摘录自JCIP
作者说,为了使上面的代码是线程安全的,我们必须使用客户端锁定。
要使此方法有效,我们必须使用List使用的相同锁,方法是使用客户端锁定或外部锁定。客户端锁定需要保护使用某个对象X的客户端代码,其中锁X用于保护自己的状态。为了使用客户端锁定,您必须知道X使用什么锁。
为什么我们不能简单地制作 List< E> 首先将对象设为私有,以使ListHelper类具有线程安全性?
答案 0 :(得分:6)
在ListHelper
的每个实例都包含自己的列表的情况下,您可以将该列表设为私有,并在ListHelper
实例上进行同步。我想这是一个有点构造的例子,用尽可能少的代码来表达观点。 IMO名称ListHelper
意味着我可以传递一个外部列表,该列表可以被多个ListHelper
实例清楚地重用。
我要说的是:给定代码不会改变list
的可见性(可能会破坏其他代码),您最好在list
上比当前ListHelper
同步实例
答案 1 :(得分:0)
首先,我们应该了解作者的目的。作者的目的是构建一个线程安全的List工具,它对包括putifAbsent方法在内的所有方法都是安全的。
ListHelper也可能有以下其他方法:
public void addList(E x)
{
list.add(x);
}
public void removeList(E x)
{
list.remove(x);
}
如果某个线程调用removeList,第二个线程调用addList,第三个线程调用putIfAbsent, 然后,因为它们是不同的锁,所以会发生错误。
答案 2 :(得分:0)
这里要说明的是,如果使用同步列表,并且想要添加另一个线程安全方法,则必须使用相同的锁。这里的目的是为了表明如果你在helper类中同步,但依赖于列表提供的同步上的其他方法(锁定列表实例 - 它将破坏线程安全。
答案 3 :(得分:0)
是的,我们可以简单地将List
class ImprovedList<T> {
private final List<T> list;
public ImprovedList(List<T> list) {
this.list = list;
}
public synchronized boolean putIfAbsent(T x) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}