1997 was the time of Java 1.1, which was still hyped for applets. Another buzz was VRML runnning in browsers. Back then I was working on a 3D chat project. I had learned the Java basics at university and at work, and cranked out a chat server / applet combination that would talk via TCP sockets using a homegrown serialization protocol. Lacking an async socket API I used one server thread per client connection that would read messages and broadcast them to other clients. I was aware of the concurrency issues to be considered, so I sync'ed accordingly on serverside data structures.
My local tests worked fine, and I uploaded my little chat system to a server, where it started attracting a decent amount of users over the next months. After a while I noticed they started complaining. Under a certain network load they had issues not being able to send/receive messages at times, until the whole server might stop responding. I remember being disappointed - I had been happy with the project's initial outcome, but the users were not.
My developer axe had not been sharp enough.
Some System.out-debugging showed that the broadcast mechanism stopped and blocked connection threads when sending messages over slow or stuck connections. Which basically meant if one receiver turned out to be slow, it could block senders as well. Socket timeouts did not change anything (it would have been a duct tape fix anyway) - sending on some connections would simply block. I had a conceptual problem. For the meantime I added a cron job that would restart the server each day. Not nice.
I concluded I needed to decouple receiving and sending, and to introduce serverside sending threads as well. I planned for queues between receiving and sending threads (so even more connection threads, not very scalable, but all I could do at that point - "luckily" the number of concurrent users never exceeded 100). This would prevent one screwed connection to affect any other connections.
But how to implement that, when all the Java 1.1 collection classes had to offer were Vector and Hashtable (no BlockingQueue), and I couldn't find any Semaphore class either?
It took me a while to dig out
how Object.wait() and Object.notify() could be applied here. No programming course had covered it, and the JavaDoc on that was slightly mystical too (remember, Google was still a small startup back then). I finally came up with this solution:
public class SenderThread extends Thread {
private Object lock;
private MyLinkedList pendingEvents;
private Connection conn;
private boolean stopped;
public SenderThread(Connection _conn) {
conn = _conn;
lock = new Object()
pendingEvents = new MyLinkedList();
stopped = false;
}
public void run() {
while (!stopped) {
synchronized(lock) {
if (pendingEvents.isEmpty()) {
try {
lock.wait();
}
catch (InterruptedException e) {
}
}
}
if (!stopped && !pendingEvents.isEmpty()) {
Object obj = (Object)pendingEvents.popFront();
conn.send(obj);
}
}
}
public void send(Object obj) {
pendingEvents.pushBack(obj);
synchronized(lock) {
lock.notify();
}
}
public void terminate() {
stopped = true;
synchronized(lock) {
lock.notify();
}
}
}
That worked, and the chat server was running like this until some years ago, when the Java plugin studdenly required applets to be signed, and certain browsers stopped supporting Java altogether. The binaries and the source can still be downloaded
here and
here (one funny detail, it originally wouldn't compile on later Java compilers, because I had used variables named "enum", which was not a reserved keyword back in Java 1.1).
|
The chat in its heyday on Windows XP (500,000 users signed up overall) |
Private side-projects like this are a great playing ground. And they are important for developers. Such projects allow to experiment, make mistakes and learn from them at low risk.
Not everything is in the textbook or taught in classroom, and at work one often is constrained to a certain technical area.
I am conducting a lot of developer interviews today, and notice the difference in skillset between those who just do what is required at work or school (and not more), and
those who are curious beyond the tasks at hand, and code in their spare time as well.
When developers
link to their development blogs, stackoverflow profiles or github pages from the CV, I can get a glimpse at those endeavours. By choosing what to work on within private projects they sharpen their developer axe, and are well prepared for tomorrow's challenges.
Similar articles: