对于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 block
e.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 block
e.printStackTrace();
}
return byteBuffer;
}
public void close() {
try {
fileChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.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;
}
@Override
public 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 block
e.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 : 12345
keyset size : 1
Accept
keyset size : 1
Accept
keyset size : 1
Read From Client : Hello From 8
keyset size : 3
Accept
Read From Client : Hello From 2
Write to client : Hello From 8
keyset size : 3
Read From Client : Hello From 5
Write to client : Hello From 2
Write to client : Hello From 8
keyset size : 3
Write to client : Hello From 5
Write to client : Hello From 2
Write to client : Hello From 8
。。。。。。。。。。。。。。。
keyset size : 10
Write to client : Hello From 7
Write to client : Hello From 1
Write to client : Hello From 5
Write to client : Hello From 3
Write to client : Hello From 9
Write to client : Hello From 2
Read From Client : Hello From 0
Write to client : Hello From 6
Write to client : Hello From 8
Write to client : Hello From 4
keyset size : 10
Write to client : Hello From 7
Write to client : Hello From 1
Write to client : Hello From 5
Write to client : Hello From 3
Write to client : Hello From 9
Write to client : Hello From 0
Write to client : Hello From 2
Write to client : Hello From 6
Write to client : Hello From 8
Write to client : Hello From 4
。。。。。。。。。。。。。。。
keyset size : 3
Write to client : Hello From 0
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 3
Write to client : Hello From 0
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 3
Write to client : Hello From 0
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 3
Write to client : Hello From 0
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 3
Write to client : Hello From 0
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 2
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 2
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 2
Write to client : Hello From 6
Write to client : Hello From 4
keyset size : 1
Write to client : Hello From 4
keyset size : 1
Write to client : Hello From 4
keyset size : 1
Write to client : Hello From 4
keyset size : 1
Write to client : Hello From 4
keyset size : 1
Write to client : Hello From 4
keyset size : 1
Write 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。
分享到:
相关推荐
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。...学习和理解Java NIO以及Netty的使用,对于提升Java网络编程的能力至关重要。
Java NIO,全称为Non-Blocking ...这个例子"一个java NIO的例子"是学习和理解Java NIO概念和机制的一个很好的起点。通过分析和运行这个示例,开发者可以更深入地理解Java NIO的工作原理,并能更好地运用到实际项目中。
首先,我们要理解Java NIO的基本概念。NIO包括以下关键组件: 1. **通道(Channels)**:通道是数据传输的途径,类似于传统IO中的流。通道可以从一个数据源(如文件或套接字)读取数据,也可以向目的地(如网络连接...
Java NIO(New Input/Output)是Java标准库中提供的一种I/O模型,与传统的BIO( Blocking I/O)相比,NIO...对于初学者来说,这些源码实例可以帮助理解Java NIO的基本用法和优势,进一步提升在实际项目中的应用能力。
首先,我们要理解Java NIO的核心组件之一——流。在Java的IO体系中,流是数据传输的抽象,它代表了数据的流向,可以是输入流(InputStream)或输出流(OutputStream)。然而,NIO中的流与传统的IO流有所不同,它们...
首先,我们要理解Java NIO的基本组件。主要包括通道(Channels)、缓冲区(Buffers)和选择器(Selectors)。通道是数据读写的目标或来源,缓冲区用于存储数据,而选择器则允许单个线程监视多个通道的事件,从而提高...
为了更好地理解Java NIO的使用方式,下面我们通过简单的代码示例来展示如何实现一个基本的NIO服务端和客户端。 **服务端代码实现** ```java package cn.nio; import java.io.IOException; import java.net....
文件"NIOSocket"可能是这个NIO Socket通信示例的源代码,可能包含了上述提到的ServerSocketChannel、SocketChannel、Selector和ByteBuffer的使用示例,通过阅读和分析这个文件,你可以更深入地理解Java NIO在实际...
总结,这个“JAVA NIO 异步通信模板服务端”示例是学习和理解Java NIO机制的好起点,它展示了如何利用NIO的非阻塞特性构建高并发的服务。在实际开发中,结合Android环境,可以进一步优化网络通信和数据交换的效率。
Java NIO的反应器模式设计与实现,首先涉及到理解Java NIO的基本概念,如通道(Channel)、缓冲区(Buffer)、选择器(Selector)等。通道是进行读写操作的基础,是连接I/O源和数据的端点。缓冲区是在NIO中用于数据...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新...通过系统学习,开发者将更好地理解Java NIO的优势,并能在适当的情况下选择使用NIO而非传统的BIO模型。
Java NIO(非阻塞I/O)是一种在Java中处理I/O操作的高效方式,它与传统的阻塞I/O模型不同。NIO全称为New Input/Output,它引入了通道...对于想要深入理解Java NIO和事件驱动编程的人来说,这是一个很好的实践案例。
首先,理解Java NIO的基本概念非常重要。NIO中的“N”代表“非阻塞”,这意味着在进行I/O操作时,程序可以继续执行其他任务,而不是等待数据传输完成。NIO的核心组件包括通道(Channels)、缓冲区(Buffers)和选择...
本资源为“基于Java NIO实现五子棋游戏”的项目文件,旨在帮助学习者深入理解Java NIO技术及其在网络编程中的应用。项目采用Java NIO库,支持非阻塞IO操作,与传统的BIO相比,NIO能提供更高效的网络和文件IO性能。本...
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新...《Java NIO》这本书由Ron Hichens著,内容详细且易懂,对于学习和理解Java NIO系统提供了宝贵的资源。
理解Java NIO中的`ByteBuffer`涉及以下关键知识点: 1. **通道(Channels)**:通道是数据的来源或目的地,如文件通道、套接字通道等。它们可以与缓冲区交互,读取或写入数据。 2. **选择器(Selectors)**:选择...
首先,让我们理解Java NIO中的关键组件: 1. **通道(Channels)**:通道类似于流,但它们可以同时读写数据,且与缓冲区直接交互。常见的通道有FileChannel、SocketChannel、ServerSocketChannel等。 2. **缓冲区...
此书对于希望深入理解Java NIO工作原理、以及如何在应用中有效利用NIO特性的开发者来说,是一本宝贵的资源。它不仅提供了理论知识,还包含了许多实际的代码示例和应用场景分析,帮助读者更好地掌握NIO的使用。
Java NIO(New Input/...总之,Java NIO提供了强大的I/O能力,但同时也需要开发者对非阻塞I/O和多路复用有深入理解,才能充分发挥其优势,避免潜在的陷阱。学习和掌握NIO,对于提升Java应用的性能和扩展性至关重要。
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种新的I/O模型,它为Java应用程序提供了更高效的数据传输...学习和理解NIO,对于开发高并发、高性能的Java应用至关重要。