`
jiayanjujyj
  • 浏览: 198459 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论
阅读更多

对于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英文高清原版

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。...学习和理解Java NIO以及Netty的使用,对于提升Java网络编程的能力至关重要。

    一个java NIO的例子

    Java NIO,全称为Non-Blocking ...这个例子"一个java NIO的例子"是学习和理解Java NIO概念和机制的一个很好的起点。通过分析和运行这个示例,开发者可以更深入地理解Java NIO的工作原理,并能更好地运用到实际项目中。

    java nio聊天室源码

    首先,我们要理解Java NIO的基本概念。NIO包括以下关键组件: 1. **通道(Channels)**:通道是数据传输的途径,类似于传统IO中的流。通道可以从一个数据源(如文件或套接字)读取数据,也可以向目的地(如网络连接...

    nio.rar_FastCopyFile.java_NIO_UseFloatBuffer.java_java nio_文件锁

    Java NIO(New Input/Output)是Java标准库中提供的一种I/O模型,与传统的BIO( Blocking I/O)相比,NIO...对于初学者来说,这些源码实例可以帮助理解Java NIO的基本用法和优势,进一步提升在实际项目中的应用能力。

    Java语言基础教程-Java NIO流篇2

    首先,我们要理解Java NIO的核心组件之一——流。在Java的IO体系中,流是数据传输的抽象,它代表了数据的流向,可以是输入流(InputStream)或输出流(OutputStream)。然而,NIO中的流与传统的IO流有所不同,它们...

    Java NIO实现多个客户端之间的消息互发,客户端与服务器完整代码

    首先,我们要理解Java NIO的基本组件。主要包括通道(Channels)、缓冲区(Buffers)和选择器(Selectors)。通道是数据读写的目标或来源,缓冲区用于存储数据,而选择器则允许单个线程监视多个通道的事件,从而提高...

    Java NIO原理 图文分析及代码实现

    为了更好地理解Java NIO的使用方式,下面我们通过简单的代码示例来展示如何实现一个基本的NIO服务端和客户端。 **服务端代码实现** ```java package cn.nio; import java.io.IOException; import java.net....

    自己写的Java NIO 同步不阻塞IO操作

    文件"NIOSocket"可能是这个NIO Socket通信示例的源代码,可能包含了上述提到的ServerSocketChannel、SocketChannel、Selector和ByteBuffer的使用示例,通过阅读和分析这个文件,你可以更深入地理解Java NIO在实际...

    JAVA NIO 异步通信模板服务端

    总结,这个“JAVA NIO 异步通信模板服务端”示例是学习和理解Java NIO机制的好起点,它展示了如何利用NIO的非阻塞特性构建高并发的服务。在实际开发中,结合Android环境,可以进一步优化网络通信和数据交换的效率。

    基于Java NIO反应器模式设计与实现

    Java NIO的反应器模式设计与实现,首先涉及到理解Java NIO的基本概念,如通道(Channel)、缓冲区(Buffer)、选择器(Selector)等。通道是进行读写操作的基础,是连接I/O源和数据的端点。缓冲区是在NIO中用于数据...

    java nio 尚硅谷 12讲 new

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新...通过系统学习,开发者将更好地理解Java NIO的优势,并能在适当的情况下选择使用NIO而非传统的BIO模型。

    nioserver.zip_NIO_event driven java_java nio_java nioserv_nioser

    Java NIO(非阻塞I/O)是一种在Java中处理I/O操作的高效方式,它与传统的阻塞I/O模型不同。NIO全称为New Input/Output,它引入了通道...对于想要深入理解Java NIO和事件驱动编程的人来说,这是一个很好的实践案例。

    java NIO 写文件

    首先,理解Java NIO的基本概念非常重要。NIO中的“N”代表“非阻塞”,这意味着在进行I/O操作时,程序可以继续执行其他任务,而不是等待数据传输完成。NIO的核心组件包括通道(Channels)、缓冲区(Buffers)和选择...

    基于Java NIO实现五子棋游戏.zip

    本资源为“基于Java NIO实现五子棋游戏”的项目文件,旨在帮助学习者深入理解Java NIO技术及其在网络编程中的应用。项目采用Java NIO库,支持非阻塞IO操作,与传统的BIO相比,NIO能提供更高效的网络和文件IO性能。本...

    Java NIO 超清中文版

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新...《Java NIO》这本书由Ron Hichens著,内容详细且易懂,对于学习和理解Java NIO系统提供了宝贵的资源。

    Java-NIO-Programming-Cookbook(含源码)

    理解Java NIO中的`ByteBuffer`涉及以下关键知识点: 1. **通道(Channels)**:通道是数据的来源或目的地,如文件通道、套接字通道等。它们可以与缓冲区交互,读取或写入数据。 2. **选择器(Selectors)**:选择...

    nio.rar_Java识别_java nio

    首先,让我们理解Java NIO中的关键组件: 1. **通道(Channels)**:通道类似于流,但它们可以同时读写数据,且与缓冲区直接交互。常见的通道有FileChannel、SocketChannel、ServerSocketChannel等。 2. **缓冲区...

    Java NIO 英文版

    此书对于希望深入理解Java NIO工作原理、以及如何在应用中有效利用NIO特性的开发者来说,是一本宝贵的资源。它不仅提供了理论知识,还包含了许多实际的代码示例和应用场景分析,帮助读者更好地掌握NIO的使用。

    java NIO技巧及原理

    Java NIO(New Input/...总之,Java NIO提供了强大的I/O能力,但同时也需要开发者对非阻塞I/O和多路复用有深入理解,才能充分发挥其优势,避免潜在的陷阱。学习和掌握NIO,对于提升Java应用的性能和扩展性至关重要。

    java NIO实例

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种新的I/O模型,它为Java应用程序提供了更高效的数据传输...学习和理解NIO,对于开发高并发、高性能的Java应用至关重要。

Global site tag (gtag.js) - Google Analytics