ServerSocket.accept -> Socket -> Register -> Selector -> Select -> Cancel Key -> Select -> SwitchToBlockMode -> ObjectInputStream -> ReadObject -> SwitchToNonBlock -> Register looks like a lot of work just for reading a writing objects.
With the solution I outlined you don't have to switch to blocking mode, it works just fine in non-blocking mode so long as you keep a little bit of state around.
Note also that "ServerSocket.accept -> Socket" is required for any solution. Excluding that, since it's common to any solution, and folding in the fact that you can do this in non-blocking mode, we have:
Register -> Selector -> Select -> deregister read ops -> OIS -> read
I've elided the extra Select because that's just part of a loop :-)
Note also that "OIS" and "read" are also common to any solution to this problem, so the extra steps for NIO are actually:
Register -> Selector -> Select -> deregister read ops
Why go through this rigamarole? To get non-blocking semantics. A non-blocking I/O style can lead to much more efficient resource usage, a cleaner higher level code base, and better overall throughput.
Is this harder than the old BIO model? Yes, it is. Any asynchronous/non-blocking solution is going to be a bit harder than a blocking/synchronous one. But blocking/synchronous models rarely scale well. So the extra steps are the cost of doing business.
Please also note that in EmberIO, none of these extra steps are visible to the user of EmberIO. Whether you're in BIO or NIO mode, you'll just get a handleEvent() callback with your object (or a byte if you're not using Objects).
Is really Sun soo blind? Together with threading and synchronization problems in server I don't see NIO as advantage against my current blocking IO solution.
When you don't understand something, blame Sun :-)
Here's an exercise for you: how well does your BIO solution work with 5,000 simultaneous socket clients? This absolutely requires 5,000 threads + overhead to do in a BIO model.
In addition - imagine a requestor thread that needs to perform 5 "expensive" remote actions which are independent of each other, but still need to be done. For jollies let's say that each takes 100 milliseconds to perform, and that some of the data going back and forth is large enough to force some blocking. In an NIO sort of model, you can fire off all 5 actions at once, and then reap the "answers" asynchronously after firing them. The total cost of this will be 100 milliseconds + some overhead. In a typical BIO model, the cost of this will be 500 milliseconds + some overhead. You can try to model an asynchronous strategy on top of BIO - but this requires even more threads on top of the thread per connection that's the bare bones minimum.
Last question for expert. Do you guess that NIO on network really bring visible speed improvement?
Alot of people initially thought of NIO as something that would reduce latency - e.g. individual request times and responses would go down. As it turns out, this isn't the case - NIO code typically elongates latency. Where NIO really shines is in reducing the amount of resources required to service requests, and in boosting overall throughput e.g. scaling to handling many requests in a reasonable time frame. Now, as I mention in my blog entry, naive use of NIO can lead to really bad latency _and_ bad throughput. So part of the reason for creating EmberIO is to solve those problems. I use NIO in a very specific manner to try to minimize latency and maximize throughput. There's obviously a balance that has to be struck here, though, and that's why EmberIO has a number of different options - so that you can tune it to your own needs. Where BIO falls down flat on its face is that is inherently un-tunable. You have a thread per connection, it's in blocking mode, and whatever latency and throughput you get is what you get. There's no way to change the equation to differing needs.
And this is also why EmberIO swings both ways :-) If you have a small number of simultaneous sockets and you want latency as low as possible, switch EmberIO into BIO mode, and you're done. If at a latter time requirements change, and you suddenly expect many more simultaneous clients, or if your I/O characteristics change radically (e.g. you're suddenly writing or reading very big objects, or remote activities are taking much longer than they were previously), then you can switch EmberIO over to a non-blocking thread pooling strategy to better handle those sorts of activities - and still not do too badly in the latency department.