【发布时间】:2013-07-10 18:32:35
【问题描述】:
我有一个单例对象。该对象声明:
List<Player> players = new ArrayList<Player>();
同一个对象还对这个arrayList指定了4个操作:
public List<Player> getPlayers() {
return players;
} // the result of this method can be used in another object as an iterator (or maybe by index-access)
和
public void removePlayer(Player player) {
players.remove(player);
}
public void addPlayer(Player player) {
players.add(player);
}
public boolean isPresent(Player player) {
if (players.constans(player)) {...
}
现在在构造函数中我是这样做的:
players = Collections.synchronizedList(new ArrayList<Player>());
但是同步这些方法的正确方法是什么。好像如果我在另一个类中使用迭代器,它仍然会通过并发修改异常。如果 2 个线程同时调用“删除”和“包含”方法,是否会发生异常?有很多线程可以访问单例,所以我想知道在性能影响最小的情况下执行此操作的方法。
【问题讨论】:
-
正如 tieTYT 所解释的,对列表的每次访问都必须同步。这是一个乌托邦的目标。因此,您不应该让任何人从您的班级之外访问该列表。或者你应该使用并发列表。
-
并发使用“contains”和“remove”会不会抛出异常?
-
如果可以接受,您可以返回列表的副本,甚至可以返回不可修改的列表副本,以确保任何更改都会失败并出现异常。对于那些认为他们可以在不使用您的 API 的情况下添加对象的人。
-
否,因为这些方法是同步的。但是,一旦您进行了迭代,或者执行了诸如
if (!list.contains(foo)) list.add(foo)之类的check-then-act 操作,您就需要显式同步。还要注意隐藏的迭代,例如new ArrayList<>(list)。
标签: java list collections concurrency