Consider these two code samples:
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;
}
}
and…
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;
}
Now, I know that accessing an array normally is very efficient. However, I know that synchronization can be costly. On the other side, atomic operations do not need to be synchronized, but I would guess that players.get(i) is not as efficient as players[i]. So, which of these samples would give me best performance if I were to use it in a game setting? I have the server designed so that each new player has a thread dedicated to them. And every time they finish connecting and logging in, they add themselves to the list of players, via addPlayer(Player). When a player disconnects, they remove themselves from the list of players, via removePlayer(Player). Since these operations are invoked from different threads, synchronization is definitely needed.
So which should I use?
Most of these questions on SO can be answered with “have you measured it” and can be very dependent upon your environment. However, whatever solution you choose:
the cost of connecting/logging in etc. across a network will massively dwarf any efficiency you’re concerned about.
This assertion:
used to be more of a concern. Synchronisation nowadays is substantially less costly.
For the above, I really wouldn’t worry about it. Get your solution working, and then determine if the above is sufficiently inefficient to warrant reworking. I see little in the above performance-related to cause me concern.