`
jiayanjujyj
  • 浏览: 197278 次
  • 性别: 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的例子 有很详细的每一步的描述,很好去理解

    Java NIO 中文全书签

    nio对于java程序员来说可能不是很好理解,但是对于C程序员来说,就是epoll的一个封装。 我本人是C程序员,对java比较感兴趣,发现java nio里面很多的东西都是对C原生api的封装,如epoll, mmap等 要是想学习 java ...

    java NIO socket聊天室

    可以作为NIO socket入门的例子,Reactor模式,重点理解key.attach, jar文件里包含了源代码 1,运行server.bat启动服务器,可以打开编辑,修改端口号 2,运行client.bat启动客户端,可以打开编辑,ip,和端口号 3...

    Java NIO总结

    Java NIO的总结, 对于新人入门理解很好, 使用Markdown编写

    javaNIO.xmind

    自己总结的java中NIO的笔记,绘制了详细的思维导图,每个思维导图中均有详细的博文解释,方便大家学习和理解,免费分享给大家。适合java的爱好者和学习者

    JAVA-NIO-DEMO

    Anontion、Applet、NIO等Demo,可以辅助理解一下相关知识点

    一站式学习Java网络编程 全面理解BIO:NIO:AIO1

    一站式学习Java网络编程 全面理解BIO:NIO:AIO1

    Netty In Action中文版.docx

    Netty是基于Java NIO的网络应用框架,如果你是Java网络方面的新手,那么本章将是你学习... 在本章的结尾,你会明白什么是Netty以及Netty提供了什么,你会理解Java NIO和异步处理机制,并通过本书的其他章节加强理解

    基于javatcpsocket通信的拆包和装包源码-DistributedSystemUsingJavaNIO:手把手教你使用JavaNIO构

    NIO框架,使得其具有很好的扩展性,也便于理解Java NIO。 一、预备知识 JavaNIO JavaNIO网上已有许多不错的文章和教程供开发者学习,如,等等,详细内容本文不再累述,这里只简要总结一下。 普通IO,也叫BIO、...

    java NIO 详解

    Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。本系列教程将有助于你学习和理解Java NIO。

    谈谈NIO的理解Java系列2021.pdf

    谈谈NIO的理解Java系列2021.pdf

    深入Hotspot源码与Linux内核理解NIO与Netty线程模型.pdf

    深入Hotspot源码与Linux内核理解NIO与Netty线程模型

    java nio server-开源

    小型简单但完整的Java NIO服务器,任何人都可以免费使用。 目前,它仅处理发送和接收字符串,并且尚未进行优化-但它易于理解并适应您的需求。

    深入了解java NIO之Selector(选择器)

    主要介绍了java NIO之Selector(选择器)的相关资料,文中讲解非常详细,实例代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

    nio-ssh:SSH协议的纯Java实现,它使用NIO网络套接字和通道

    nio-ssh 当前状态 1-尚不可用 概述 该库是SSH协议(客户端和服务器)的纯... 通过拥有清晰简洁的文档(包括有关所有方法的JavaDoc,甚至包括私有方法),我们希望使该库易于理解和实现。 通过具有极高的单元测试覆盖

    尚硅谷JAVA基础笔记吐血整理

    尚硅谷java教程全程跟听,手动整理,从面向对象开始按章节按课时整理,适合对照视频作为笔试使用/java知识脉络梳理/八股理解背诵

    Java NIO:浅析I/O模型

    在进入Java NIO编程之前,我们先来讨论一些比较基础的知识:I/O模型。下面本文先从同步和异步的概念 说起,然后接着阐述了阻塞和非阻塞的区别,接着介绍了阻塞IO和非阻塞IO的区别,然后介绍了同步IO和异步IO的区别,...

    深入理解Apache Mina (6)---- Java Nio ByteBuffer与Mina ByteBuffer的区别

    NULL 博文链接:https://chinaestone.iteye.com/blog/468138

    简单了解JAVA NIO

    主要介绍了JAVA NIO的的相关资料,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下

    nio入门 IBM教材,pdf格式

    为了最大程度地从这里的讨论中获益,您应该理解基本的 Java 编程概念,如类、继承和使用包。多少熟悉一些原来的 I/O 库(来自 java.io.* 包)也会有所帮助。 虽然本教程要求掌握 Java 语言的工作词汇和概念,但是不...

Global site tag (gtag.js) - Google Analytics