the problem is another:
L2J: uses NIO = 1 Thread = 1 Socket
L2off: uses IOCP (overlapped ports, works only with win2k3, win2k and, limited, winXP): 1 Thread = N Sockets (usually is 2 Threads for every CPU plus 1 Thread dedicated to the "Accept" of the connection request from the client)
The cause that makes L2J sink is just this (and also bad coding, but the bigger thing is this). Of course no way to do IOCP under Java (too much "free-OS" language), same for Mono (on Linux IOCP doesn't exists, but someone said me that is possible to do something like this on openBSD... dunno.)
In C++/Delphi/C#/VB, instead, you can do it.
L2d, my freezed "porting" of l2j to delphi (but using DB of L2off), is using IOCP and i have successfully tested it with I/O with 10k users connected for 1 hour... (just junk data,don't think that was working with the L2 client!!)