考虑这两个代码示例:
private final Player[] players = new Player[MAX_PLAYERS + 1];
private int playerCount;
public boolean addPlayer(Player player) {
synchronized (players) {
for (int i = 1; i < players.length; i++) {
if (players[i] == null) {
players[i] = player;
playerCount++;
player.setIndex(i);
return true;
}
}
return false;
}
}
public void removePlayer(Player player) {
synchronized (players) {
players[player.getIndex()] = null;
playerCount--;
}
}
public Player[] getPlayers() {
synchronized (players) {
return players;
}
}
public int getPlayerCount() {
synchronized (players) {
return playerCount;
}
}
和...
private final AtomicReferenceArray<Player> players = new AtomicReferenceArray<Player>(MAX_PLAYERS + 1);
private final AtomicInteger playerCount = new AtomicInteger();
public boolean addPlayer(Player player) {
for (int i = 1; i < players.length(); i++) {
if (players.get(i) == null) {
players.set(i, player);
playerCount.incrementAndGet();
player.setIndex(i);
return true;
}
}
return false;
}
public void removePlayer(Player player) {
players.set(player.getIndex(), null);
playerCount.decrementAndGet();
}
public AtomicReferenceArray<Player> getPlayers() {
return players;
}
public AtomicInteger getPlayerCount() {
return playerCount;
}
现在,我知道正常访问数组非常有效。但是,我知道同步可能代价高昂。另一方面,原子操作不需要同步,但我猜测players.get(i)
不如players[i]
有效。那么,如果我在游戏环境中使用它,哪些样本会给我最好的表现?我设计的服务器使每个新玩家都有专门的线程。每次他们完成连接和登录后,他们都会通过addPlayer(Player)
将自己添加到玩家列表中。当玩家断开连接时,他们会通过removePlayer(Player)
将自己从玩家列表中删除。由于这些操作是从不同的线程调用的,因此绝对需要同步。
那我该使用哪个?
答案 0 :(得分:2)
关于SO的大多数问题都可以用“你测量过吗”来回答,并且可能非常依赖于你的环境。但是,无论您选择何种解决方案:
每次他们完成连接和登录后,他们都会添加 他们自己到玩家列表,通过addPlayer(播放器)
通过网络连接/登录等的成本将大大使您关注的任何效率相形见绌。
这个断言:
但是,我知道同步可能代价高昂
过去更受关注。如今的同步成本要低得多。
对于上述内容,我真的不担心。让您的解决方案正常工作,然后确定上述内容是否足够低效以保证重新处理。我在上面的表现中看不到与我有关的事情。
答案 1 :(得分:1)
只有选项1是线程安全的。
选项2以非线程安全的方式检查player[i]
是否为空。
答案 2 :(得分:1)
这是编写它的最简单方法
private final List<Player> players = new CopyOnWriteArrayList(); // thread safe
public boolean addPlayer(Player player) {
return players.add(player);
}
public void removePlayer(Player player) {
players.remove(player);
}
public List<Player> getPlayers() {
return players;
}
public int getPlayerCount() {
return players.size();
}
注意:这不起作用
public Player[] getPlayers() {
synchronized (players) {
return players;
}
}
因为您将无法以安全的方式使用返回的数组。鉴于您只访问最终字段,synchronized将不会执行任何操作。