I really love Java NIO, and I really want to apply Java NIO to my current system, but when I created the application to compare between Java IO and NIO, it disappointed me.
Here are my 2 samples (I did not put all the source code)
Java IO
public class BlockingServerClient { private static final Logger log = Logger.getLogger(BlockingServerClient.class.getName()); static final ExecutorService service = Executors.newCachedThreadPool(); public static void main(String[] args) throws InterruptedException { int port = Integer.parseInt(args[0]); BlockingServerClient server = new BlockingServerClient(); Server sr = server.new Server(port); service.submit(sr); } private class Server implements Runnable { ..... public void run() { ServerSocket ss = null; try { ss = new ServerSocket(localPort); log.info("Server socket bound to " + localPort); while (true) { Socket client = ss.accept(); log.info("Accepted connection from " + client.getRemoteSocketAddress()); service.submit(new SocketClient(client)); } } catch (IOException e) { log.log(Level.SEVERE, "Server error", e); } finally { ..... } } } private class SocketClient implements Runnable { ..... public void run() { InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress(); socketInfo = String.format("%s:%s", addr.getHostName(), addr.getPort()); log.info("Start reading data from " + socketInfo); try { in = new BufferedReader( new InputStreamReader(socket.getInputStream())); String input; while ((input = in.readLine()) != null) { log.info(String.format("[%s] %s", socketInfo, input)); log.info("Socket " + socketInfo + " thread sleep 4s"); TimeUnit.SECONDS.sleep(4); } } catch (Exception ex) { log.log(Level.SEVERE, "Socket error", ex); } finally { ..... } } } }
Java NIO
public class NonBlockingServerClient { private static final Logger log = Logger.getLogger(NonBlockingServerClient.class.getName()); public static void main(String[] args) { int port = Integer.parseInt(args[0]); EventLoopGroup boss = new NioEventLoopGroup(); EventLoopGroup worker = new NioEventLoopGroup(); try { NonBlockingServerClient sc = new NonBlockingServerClient(); Server server = sc.new Server(port, boss, worker); server.run(); } catch (Exception e) { log.log(Level.SEVERE, "Error", e); } finally { boss.shutdownGracefully(); worker.shutdownGracefully(); } } private class Server { ..... public void run() { log.info("Start Server bootstrap"); ServerBootstrap b = new ServerBootstrap(); b.group(boss, worker) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipe = ch.pipeline(); pipe.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipe.addLast(new StringDecoder()); pipe.addLast(new ClientHandler()); } }); ChannelFuture future = null; try { future = b.bind(port).sync(); future.channel().closeFuture().sync(); } catch (InterruptedException e) { log.log(Level.SEVERE, "Server binding error", e); future.channel().close(); } } } private class ClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { log.info(String.format("[%s] %s", ctx.channel().remoteAddress(), msg)); log.info(ctx.channel().remoteAddress() + " sleep 4s"); TimeUnit.SECONDS.sleep(4); } } }
Client
public class Client { private static final Logger log = Logger.getLogger(Client.class.getName()); public static void main(String[] args) throws InterruptedException { int port = Integer.parseInt(args[0]); for (int i = 0; i < 10; i++) { Client cl = new Client("localhost", port); cl.start(); TimeUnit.MILLISECONDS.sleep(500); } } String host; int port; public Client(String host, int port) { this.host = host; this.port =port; } public void start() { log.info("Start client running"); Socket socket = null; String info = ""; try { socket = new Socket(host, port); InetSocketAddress addr = (InetSocketAddress) socket.getLocalSocketAddress(); info = String.format("%s:%s", addr.getHostName(), addr.getPort()); int count = 10; OutputStream out = socket.getOutputStream(); while (count > 0) { String outStr = "Output-" + count + "\n"; out.write(outStr.getBytes()); out.flush(); count--; } out.write((info + "-Finish sending").getBytes()); out.flush(); } catch (Exception e) { log.log(Level.SEVERE, "Client error", e); } finally { try { socket.close(); log.info(info + "-Client close"); } catch (IOException e) { log.log(Level.SEVERE, "Closing client error", e); } } } }
The client at startup will create 10 clients connected to the server. After several starts and controls, I did not find any differences between Java IO and NIO.
If the number of clients changed by 500, I found that java IO did create 500 threads, however, data consumption is very fast. In contrast, there were much fewer threads in the java NIO application than in another, but data consumption was slow, and it took more time to complete.
So what is the real advantage of Java NIO? Create fewer threads to save memory, but slower in performance.
Or, I could do it wrong.