I'm currently working on a multiplayer server in Java which is using seperate threads to listen for incoming data via TCP.
Now, i've worked in java and did some minor multithreaded applications before, but i've never done anything of such a scale.
My problem is that even though the server "works" the code itself is quite ugly and thus i try to refractor it without sacrificing a huge amount of performance.
So i create 2 threads on the server for each connected client:
- The first thread is waiting for incoming TCP messages
- The second one is processing data, sending data back to the client (without being blocked by the TCP thread), doing movement validation, etc...
Now here is the thing:
The first thread which handles the incoming TCP data also sends data back or does some other funky stuff (like setting specifig flags for the player or accessing other systems to update player coordinates, etc...)
This makes the Code quite ugly as i have stuff like this lying around (on the TCP thread):
case 201: //incoming message ID
//reset run
player.getCheckpointList().getLock().writeLock().lock();
player.getCheckpointList().clear();
player.getCheckpointList().getLock().writeLock().unlock();
break;
case 202:
//checkpoint activated
int time = StreamConverter.buffer_read_u32(input);
player.getCheckpointList().getLock().writeLock().lock();
player.getCheckpointList().add(time);
player.getCheckpointList().getLock().writeLock().unlock();
break;
case 203:
//goal activated
long goalTime = StreamConverter.buffer_read_u32(input);
//TODO: check if checkpoint count is valid
PlayerClientData data = player.getPlayerDataCopy();//playerDataCopy to avoid multithreading issues.
int hash = data.getName().hashCode();//has to be more specific (like using the playerskin in addition to the name, etc...)
//TODO: Better hashcode for player identification
server.getGameState().getHighscoreState().addEntry(new LeaderboardEntry(goalTime,data.getName(),(byte) 1,hash));//add to highscoreState (replaces entry if one already exists)
//clear checkpoint list
player.getCheckpointList().getLock().writeLock().lock();
player.getCheckpointList().clear();
player.getCheckpointList().getLock().writeLock().unlock();
break;
The thread which handles the incoming TCP traffic does access other parts of the systems and has the ability to send messages back. This means that it has to use locks (in one form or another) to prevent race conditions.
Now i figured that it would be a good idea to transfer all the response code to the other Thread (which is doing the exact same stuff anyway) and use a messaging Queue to send messages from one thread to the other.
This would:
A. Make the TCP thread have only one task: Listening to TCP messages and notifying the other thread without worrying about responding to the client or updating data on the serverside.
B. Make the other thread the only place where any kind of data is processed or sent to the client. (Which would make it cleaner and more unified.)
Now the issue which i'm worrying about is the performance of messages:
The only way i can think of implementing that is some kind of message objects which are put into the queue by one thead and then read by the other thread.
Now, given that Java is using a GC and every single message would require allocating a new object on the heap, this could be quite problematic in the long run especially as i want to support up to 64 clients in realtime. (64 Threads would be generating a lot of garbage in a very short time which would require more frequent GC pauses. Although i have no idea how big of an performance impact this would have.)
Does anyone have experience with message queues and their performance impact?
Is this a common solution for servers (or any kind of multithreaded application?)