首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

懂得Java NIO

2012-11-01 
理解Java NIO对于Java NIO,总是看见别人写,使用Java NIO能够提高性能,比BIO的性能要好挺多,但是一直未能深

理解Java NIO

对于Java NIO,总是看见别人写,使用Java NIO能够提高性能,比BIO的性能要好挺多,但是一直未能深入的研究,不太清楚NIO到底是怎么来提高性能的,Non-blocking到底体现在哪里。这几天搜索了一个,找到一些讲的比较好的文章,并实际写了一个小的程序来理解一下,对NIO有了更进一步的理解。

?

所参考查询的资料如下:

1. JAVA NIO 简介?

http://www.iteye.com/topic/834447

帖子讲解了NIO相关的知识,比较好的比较和总结了BIO和NIO的区别,指出了为什么NIO的性能比BIO要好,解答了我一直的疑问。帖子后面的回复非常有用,一定要看。

2. 使用Java NIO编写高性能的服务器?

http://tenyears.iteye.com/blog/40489

代码非常好,通过这个代码可以更好的理解NIO

?

下面根据2里面的代码写了一个程序,客户端想服务器请求下载文件,如果文件比较大,比较耗时,采用BIO的方式的话,如果起100个线程,只能100个client进行下载,第101个客户就得等待。而且CPU需要不断的切换来知道哪个线程中的IO读写可以进行了,开销比较大。使用NIO后,如果有IO读写到来,服务器就会得到相关的事件,开始进行读写,这样的开销比BIO要小很多,通过一个线程轮询事件就能完成。

?

看一下代码,里面加了一些log,有助于理解NIO

Server端的代码为:

package com.jyj.test.server;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.channels.FileChannel;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.nio.charset.CharsetDecoder;import java.util.Iterator;import java.util.Set;public class NIOServer {        private static final int BLOCK_SIZE = 4096;        private Selector selector;    private String file = "D:\\Learning\\Java\\HowTomcatWorksApps.zip";    private ByteBuffer buffer = ByteBuffer.allocate(BLOCK_SIZE);    private CharsetDecoder charsetDecoder;        public NIOServer(int port) throws IOException {selector = this.getSelector(port);Charset charset = Charset.forName("UTF-8");charsetDecoder = charset.newDecoder();    }        private Selector getSelector(int port) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();Selector selector = Selector.open();serverSocketChannel.socket().bind(new InetSocketAddress(port));serverSocketChannel.configureBlocking(false);serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);return selector;    }        public void listen() {while(true) {    try {selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> it = selectionKeys.iterator();System.out.println("keyset size : " + selectionKeys.size());while (it.hasNext()) {    SelectionKey selectionKey = it.next();    it.remove();    handleKey(selectionKey);}    } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();    }    }    }        private void handleKey(SelectionKey key) throws IOException {if (key.isAcceptable()) {    System.out.println("Accept");    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();    SocketChannel channel = serverSocketChannel.accept();    channel.configureBlocking(false);    channel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {    SocketChannel channel = (SocketChannel) key.channel();    int count = channel.read(buffer);    if (count > 0) {buffer.flip();CharBuffer charBuffer = charsetDecoder.decode(buffer);String clientName = charBuffer.toString();System.out.println("Read From Client : " + clientName);SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_WRITE);selectionKey.attach(new HandleClient(clientName));    } else {channel.close();    }    buffer.clear();} else if (key.isWritable()) {    SocketChannel channel = (SocketChannel) key.channel();    HandleClient handleClient = (HandleClient) key.attachment();    ByteBuffer buffer = handleClient.readBlock();    System.out.println("Write to client : " + handleClient.getClentName());    if (buffer != null) {channel.write(buffer);    } else {handleClient.close();channel.close();    }}    }        private class HandleClient {private FileChannel fileChannel;private ByteBuffer byteBuffer;private String clientName;public HandleClient(String clientName) throws FileNotFoundException {    fileChannel = new FileInputStream(file).getChannel();    byteBuffer = ByteBuffer.allocate(BLOCK_SIZE);    this.clientName = clientName;}public ByteBuffer readBlock() {    try {byteBuffer.clear();int count = fileChannel.read(byteBuffer);byteBuffer.flip();if (count < 0) {    return null;}    } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();    }        return byteBuffer;}public void close() {    try {fileChannel.close();    } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();    }}public String getClentName() {    return clientName;}    }        public static void main(String [] args) {int port = 12345;try {    NIOServer server = new NIOServer(port);    System.out.println("Listening on : " + port);    while (true) {server.listen();    }} catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();}    }}

?

client端的代码为:

package com.jyj.test.client;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.nio.charset.CharsetEncoder;import java.util.Iterator;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class NIOClient {    static int SIZE = 10;    static InetSocketAddress address = new InetSocketAddress("localhost", 12345);    static CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();        static class DownloadFile implements Runnable {int index;public DownloadFile(int index) {    this.index = index;}@Overridepublic void run() {    long start = System.currentTimeMillis();    try {SocketChannel client = SocketChannel.open();client.configureBlocking(false);Selector selector = Selector.open();client.register(selector, SelectionKey.OP_CONNECT);client.connect(address);ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);int total = 0;while(true) {    boolean isExit = false;    selector.select();    Iterator<SelectionKey> it = selector.selectedKeys().iterator();    while (it.hasNext()) {SelectionKey selectionKey = (SelectionKey) it.next();it.remove();if (selectionKey.isConnectable()) {    SocketChannel channel = (SocketChannel) selectionKey.channel();    if (channel.isConnectionPending()) {channel.finishConnect();    }    channel.write(encoder.encode(CharBuffer.wrap("Hello From " + index)));    channel.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) {    SocketChannel channel = (SocketChannel) selectionKey.channel();    int count = channel.read(buffer);    if (count > 0) {total += count;buffer.clear();    } else {channel.close();isExit = true;break;    }}    }    if (isExit) {break;    }}double last = (System.currentTimeMillis() - start) * 1.0 / 1000;System.out.println("Thread " + index + " downloaded " + total + " bytes in " + last + "seconds.");    } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();    }    }    }        public static void main(String [] args) {ExecutorService pool = Executors.newFixedThreadPool(SIZE);for (int i = 0; i < SIZE; i++) {    pool.execute(new DownloadFile(i));}pool.shutdown();    }}
?

server端的输出结果如下:

Listening on : 12345keyset size : 1Acceptkeyset size : 1Acceptkeyset size : 1Read From Client : Hello From 8keyset size : 3AcceptRead From Client : Hello From 2Write to client : Hello From 8keyset size : 3Read From Client : Hello From 5Write to client : Hello From 2Write to client : Hello From 8keyset size : 3Write to client : Hello From 5Write to client : Hello From 2Write to client : Hello From 8。。。。。。。。。。。。。。。keyset size : 10Write to client : Hello From 7Write to client : Hello From 1Write to client : Hello From 5Write to client : Hello From 3Write to client : Hello From 9Write to client : Hello From 2Read From Client : Hello From 0Write to client : Hello From 6Write to client : Hello From 8Write to client : Hello From 4keyset size : 10Write to client : Hello From 7Write to client : Hello From 1Write to client : Hello From 5Write to client : Hello From 3Write to client : Hello From 9Write to client : Hello From 0Write to client : Hello From 2Write to client : Hello From 6Write to client : Hello From 8Write to client : Hello From 4。。。。。。。。。。。。。。。keyset size : 3Write to client : Hello From 0Write to client : Hello From 6Write to client : Hello From 4keyset size : 3Write to client : Hello From 0Write to client : Hello From 6Write to client : Hello From 4keyset size : 3Write to client : Hello From 0Write to client : Hello From 6Write to client : Hello From 4keyset size : 3Write to client : Hello From 0Write to client : Hello From 6Write to client : Hello From 4keyset size : 3Write to client : Hello From 0Write to client : Hello From 6Write to client : Hello From 4keyset size : 2Write to client : Hello From 6Write to client : Hello From 4keyset size : 2Write to client : Hello From 6Write to client : Hello From 4keyset size : 2Write to client : Hello From 6Write to client : Hello From 4keyset size : 1Write to client : Hello From 4keyset size : 1Write to client : Hello From 4keyset size : 1Write to client : Hello From 4keyset size : 1Write to client : Hello From 4keyset size : 1Write to client : Hello From 4keyset size : 1Write to client : Hello From 4

?

client端的输出结果为:

Thread 5 downloaded 3844845 bytes in 1.938seconds.Thread 2 downloaded 3844845 bytes in 1.953seconds.Thread 1 downloaded 3844845 bytes in 1.953seconds.Thread 8 downloaded 3844845 bytes in 1.922seconds.Thread 9 downloaded 3844845 bytes in 1.922seconds.Thread 7 downloaded 3844845 bytes in 1.953seconds.Thread 3 downloaded 3844845 bytes in 1.969seconds.Thread 0 downloaded 3844845 bytes in 1.969seconds.Thread 6 downloaded 3844845 bytes in 1.953seconds.Thread 4 downloaded 3844845 bytes in 1.953seconds.

?

最近建议找一下linux或者windows的socket编程方面的书看一下,能够更好的理解IO方面的知识,包括Java 7中的AIO。

热点排行