我有一个单身对象。该对象声明:
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>());
但是同步这些方法的正确方法是什么。好像我在另一个类中使用iterator,它仍然会通过并发修改异常。如果2个线程同时调用“remove”和“contains”方法,是否会发生异常?有很多线程可以访问单例,所以我想知道以最小的性能命中来执行此操作的方法。
答案 0 :(得分:11)
The documentation answers your question.
当迭代时,用户必须手动同步返回的列表:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
至于contains
和remove
,您不必手动同步。我正在查看Collections
的源代码,看起来它适合你:
public boolean contains(Object o) {
synchronized (mutex) {return c.contains(o);}
}
public boolean remove(Object o) {
synchronized (mutex) {return c.remove(o);}
}
如果你必须自己做这些事情,它就不会是同步列表。
答案 1 :(得分:6)
如果您不打算更新它,请经常使用CopyOnWriteArrayList否则@ tieTYT的建议。
您也可以通过返回列表的副本而不是getPlayers
中的实际列表来自行管理。 (如果您使用的是Collections.synchronizedList
)
public List<Player> getPlayers(){
synchronized(list){
Collections.unmodifiableList(new ArrayList<Player>(list));
}
}
这有添加/删除后列表过期的副作用
修改 窃取Grzegorz对unmodifiableList
的建议