没有这样的public 方法可以让您控制同步集合将使用的互斥锁。因此,如果不是允许您指定互斥锁的列表,则必须以这种灵活性来实现更高级别的操作,例如:
public static <T> boolean addIfNew(List<T> target, T value, Object mutex) {
synchronized (mutex) {
return !target.contains(value) && target.add(value);
}
}
然后可以用作
List<String> synchedList=Collections.synchronizedList(new ArrayList<String>());
addIfNew(synchedList, "foo", synchedList);
这是因为synchronizedList 返回的列表将自己用作互斥体。与its documentation比较:
强调我的
当迭代它时,用户必须手动在返回的列表上同步:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
实现允许在内部使用不同互斥对象的原因是您可以创建sub lists,并且同步列表的子列表将在后备列表实例上同步,而不是在其自身上同步(同样适用于Vector.subList)。因此,当您将子列表传递给高级方法时,将原始同步列表作为互斥体传递是至关重要的。
Collection 视图也适用于地图:
Collections.synchronizedMap:
当迭代其任何集合视图时,用户必须在返回的地图上手动同步:
Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn't be in synchronized block
...
synchronized (m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
对此进行了简化。如果您确保对集合的所有访问都发生在您的方法中,则这些方法可能会在任意互斥锁上达成一致,并且如果一致地在该互斥锁上同步,则这些方法是线程安全的。当然,此时不需要集合本身进行额外的同步,但这就是它的全部意义所在:
在实践中,您几乎找不到这些同步集合的任何有用场景。任何重要的操作都需要对集合进行多次访问,因此需要手动或更高级的同步,这使得低级同步过时了。
考虑将同步集合传递给与集合一起工作的任意方法并自动获得线程安全而无需额外同步是很诱人的,但由于这仅在所述方法包含对集合的一次访问时才有效,因此您不会发现任何有用的现实生活方法。
因此,底线是您将始终必须使您的代码线程安全并控制对集合的访问,因此永远不需要同步集合。