文档章节

java的NIO概述

EveryDayNew
 EveryDayNew
发布于 2015/12/28 23:47
字数 1491
阅读 157
收藏 11
点赞 0
评论 0

       概述

 java中io输入输出流是阻塞的,如BufferedReader的readLine(),InputStrean的read()方法。当程序没有读到有效数据,程序将在此处阻塞。比较典型的是,在用socket传递数据,如果发送数据的一方,没有关闭流,接收数据的一方,接收数据后将一直阻塞。面向流的输入输出,最底层一次只能处理一个字节,因此效率不高。

    jdk1.4提供了新的IO即NIO。

    NIO中有三个重要的特性。

    Channel,通道。模拟传统的输入输出流,既可以做输入又可以做输出。

    Buffer,缓冲。本质是一个数组,发送到Channel的所有对象都必须先放到Buffer中。读取数据也先读到Buffer。

    Selector。selector允许单线程处理多个Channel,可监控多个服务

    Buffer简介

    buffer中有三个重要概念:容量(capactiy)、界限(limit)和位置(position,带读取数据的下标)。

    这些值满足如下关系:0<=mark<=position<=limit<=capacity

    Buffer中包含两个重要的方法flip和clear,flip为从Buffer中取出数据做准备,clear则向Buffer中装入数据做准备。

    当Buffer中装入数据结束后,调用flip方法,该方法将limit设置为position所在的位置,将position设为0,这样Buffer中读数据总是从0开始,做好输出准备。当Buffer输出数据结束,Buffer调用clear方法,clear方法不是清空Buffer的数据,它仅仅将poition置为0,将limit置为capacity,这样为再次向Buffer装入数据做准备,此时原先的数据没有清除,新写的数据会替换原先的数据。

    Channel简介

    所有的Channel都不应该通过构造器来直接创建,而是通过InputStream、OutputStream的getChannel方法来返回对应的Channel。

    Channel中最常用的三类方法是map、read和write,其中map方法用于将Channel对应的部分或全部数据映射为ByteBuffer;而read或write方法用于向Buffer读取写入数据。

static void channelTest() throws Exception{
		FileInputStream is = new FileInputStream(new File("G:/百无聊赖.txt"));
		FileOutputStream out = new FileOutputStream(new File("G:/ttt.txt"));
		FileChannel readChannel = is.getChannel();
		FileChannel writechannel = out.getChannel();
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		while(readChannel.read(buffer)!=-1){
			buffer.flip();//准备取出数据
			writechannel.write(buffer);
			buffer.clear();//准备装入数据
		}
		writechannel.close();
		readChannel.close();
		out.close();
		is.close();
	}

因为jdk对之前的IO采用nio的机制重新实现了,所以直接使用nio对数据进行读写并不常用。使用channel的map方法,进行内存映射,可以快速的读写数据,但是这种方式不安全,仅使用与读数据。NIO最常用的功能应该是它的Selector。

Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。 

如下两篇博文对NIO包括selector的介绍都不错

http://www.iteye.com/magazines/132-Java-NIO#579

http://www.xuebuyuan.com/1600515.html 

下面构建一个小例子对比下NIO和IO服务器

服务端代码:

package com.base.nio;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
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;

public class Server {

	public static void main(String[] args) throws Exception{
//		nioServer();
		socketServer();
	}
	public static void nioServer() throws Exception{
		int port=9999;
		Selector selector=Selector.open();
		ServerSocketChannel ssc=ServerSocketChannel.open();
		ServerSocket serverSocket=ssc.socket();
		serverSocket.bind(new InetSocketAddress(port));
		System.out.println("Server listen on port: "+port);
		ssc.configureBlocking(false);
		ssc.register(selector, SelectionKey.OP_ACCEPT);
		while(true){
			int nKeys=selector.select();
			if(nKeys>0){
				for (SelectionKey key : selector.selectedKeys()) {
					if(key.isAcceptable()){
						ServerSocketChannel server=(ServerSocketChannel) key.channel();
						SocketChannel sc=server.accept();
						if(sc==null){
							continue;
						}
						sc.configureBlocking(false);
						sc.register(selector, SelectionKey.OP_READ);
					}
					else if(key.isReadable()){
						ByteBuffer buffer=ByteBuffer.allocate(1024);
						SocketChannel sc=(SocketChannel) key.channel();
						int readBytes=0;
						readBytes = sc.read(buffer);//如果客户端传来的数据长度超过1024,会丢失报文。
						buffer.flip();
						if(readBytes>0){
							String message =Charset.forName("UTF-8").decode(buffer).toString();
							System.out.println("Message from client: "+ message);
							if("quit".equalsIgnoreCase(message.trim())){
								sc.close();
								selector.close();
								System.out.println("Server has been shutdown!");
								System.exit(0);
							}
							String outMessage="Server response:"+message;
							sc.write(Charset.forName("UTF-8").encode(outMessage));
						}
					}
				}
				selector.selectedKeys().clear();
			}
		}
	}

	public static void socketServer() throws IOException, InterruptedException, Exception {
		ServerSocket ss = new ServerSocket(9999);
		while(true){
			Socket socket = ss.accept();
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			String getMsg = br.readLine();
			if("quit".equalsIgnoreCase(getMsg.trim())){
				ss.close();
				System.out.println("Server has been shutdown!");
				System.exit(0);
			}
			System.out.println(getMsg);
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			bw.write("Hello Client");
			bw.newLine();
			bw.flush();
			Thread.sleep(10000);
			Client.close(socket, null, bw, br);
		}
	}

}

客户端代码:

package com.base.nio;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class Client implements Runnable{

	public static void main(String[] args) throws Exception{
		for(int i=0;i<10;i++){
			Client c = new Client();
			Thread thread = new Thread(c);
			thread.start();
		}
	}
	@Override
	public void run() {
		Socket socket = null;
		OutputStream out = null;
		BufferedWriter bw = null;
		BufferedReader br = null;
		try {
			socket = new Socket("127.0.0.1", 9999);
			out = socket.getOutputStream();
			bw = new BufferedWriter(new OutputStreamWriter(out));
			bw.write("Hello Server");
			bw.newLine();
			bw.flush();
			Thread.sleep(10000);
			br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			String retMsg = br.readLine();
			System.out.println(retMsg+Thread.currentThread().getName());
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				Client.close(socket, out, bw,br);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void close(Socket socket, OutputStream out, BufferedWriter bw,BufferedReader br) throws Exception{
		if(br!=null)
			br.close();
		if(bw!=null)
			bw.close();
		if(out!=null)
			out.close();
		if(socket!=null)
			socket.close();
	}
}

通过运行分析,发现nio是非阻塞的,不用等每一个客户端的连接请求完成,就可以进行下一个连接。而传统的socket会等待客户端的每个请求完成,才去连接下个客户端请求。

nio是通过while(true)进行轮询,来不断监听客户端的请求状态。而socket是通过阻塞的方式来等待客户端的请求状态。

感觉NIO最大的优势就在于它的非阻塞,减少了等待客户的响应。如果使用socket要想达到同样的效果,必须使用线程池,使用线程池就相对耗资源些。

至于监听多个chanel,也就是同时监听多个端口。比如以上例子,9999用于监听客户端会话。如果服务端还要一个8888端口,来控制其他服务,比如关闭服务等等。传统的socket也必须用多线程来实现。

但是感觉NIO采用这种轮的方式,不是很优雅。可能我了解的不多吧。

© 著作权归作者所有

共有 人打赏支持
EveryDayNew
粉丝 5
博文 25
码字总数 31409
作品 0
杭州
程序员
Java NIO AsynchronousFileChannel

原文链接 , 原文作者:Jakob Jenkov, 翻译:Neil Hao 在Java 7,AsynchronousFileChannel 被添加到了Java NIO中。使用AsynchronousFileChannel可以实现异步地读取和写入文件数据。 创建一个A...

Neil_Hao ⋅ 01/20 ⋅ 0

Java NIO 系列教程 -- delete

(一) Java NIO 概述 Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Selector 构成了核心的A...

数据之美 ⋅ 2013/06/09 ⋅ 4

Java 使用 happen-before 规则实现共享变量的同步操作

前言 熟悉 Java 并发编程的都知道,JMM(Java 内存模型) 中的 happen-before(简称 hb)规则,该规则定义了 Java 多线程操作的有序性和可见性,防止了编译器重排序对程序结果的影响。按照官方的...

stateIs0 ⋅ 01/20 ⋅ 0

Jenkins 教程(一)实现自动化打包及邮件通知

个人不喜欢装腔作势一堆专业术语放上去,让大多数人看不懂来提升逼格(所谓的专家),所以我简单的介绍jenkins是干啥的。本文使用jenkins,就是让它把git仓库里的东西取出来,然后在jenkins容器...

FantJ ⋅ 05/26 ⋅ 0

JavaWeb07-HTML篇笔记(二)

1.1 案例一:使用JDBC完成CRUD的操作:1.1.1 需求: 对分类管理使用JDBC进行CRUD的操作. 1.1.2 分析:1.1.2.1 技术分析: 【JDBC的概述】 Ø JDBC:Java DataBase Connectivity Java数据库的连...

我是小谷粒 ⋅ 05/16 ⋅ 0

培训云计算学校,虚拟机基本结构讲解

我们要对JVM虚拟机的结构有一个感性的认知。毕竟我们不是编程人员,认知程度达不到那么深入。一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序时,一个虚拟机...

长沙千锋 ⋅ 05/17 ⋅ 0

阿里巴巴菜鸟Java一面11个问题,你会几个呢?

近日,w3cschool app开发者头条上分享了阿里菜鸟Java程序员一些面试题。 这吸引了不少程序员小伙伴们的注意。 在分享阿里菜鸟Java程序员面经前,来看下Java面试一些面试经验分享: 0、Java高...

W3Cschool ⋅ 04/03 ⋅ 0

Java NIO之Selector(选择器)

历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) Java NIO 之 Channel(通道) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂redis集群原理及搭建与使用 超详细的Jav...

山川_84b6 ⋅ 05/16 ⋅ 0

Java NIO 之 Channel(通道)

历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂redis集群原理及搭建与使用 一 Channel(通道)介绍 通常来说NIO中的所...

山川_84b6 ⋅ 05/15 ⋅ 0

Java 5 、6、 7中新特性

JDK5新特性(与1.4相比)【转】 1 循环 for (type variable : array){ body} for (type variable : arrayList){body} 而1.4必须是: for (int i = 0; i < array.length; i++){ type variabl......

thinkyoung ⋅ 2014/10/14 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

OSChina 周六乱弹 —— 假如你被熊困到树上

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @小小编辑:推荐歌曲《如果写不出好的和弦就该在洒满阳光的钢琴前一起吃布丁》 《如果写不出好的和弦就该在洒满阳光的钢琴前一起吃布丁》- 谢...

小小编辑 ⋅ 33分钟前 ⋅ 2

vbs 取文件大小 字节

dim namedim fs, s'name = Inputbox("姓名")'msgbox(name)set fs = wscript.createobject("scripting.filesystemobject") 'fs为FSO实例if (fs.folderexists("c:\temp"))......

vga ⋅ 今天 ⋅ 1

高并发之Nginx的限流

首先Nginx的版本号有要求,最低为1.11.5 如果低于这个版本,在Nginx的配置中 upstream web_app { server 到达Ip1:端口 max_conns=10; server 到达Ip2:端口 max_conns=10; } server { listen ...

算法之名 ⋅ 今天 ⋅ 0

Spring | IOC AOP 注解 简单使用

写在前面的话 很久没更新笔记了,有人会抱怨:小冯啊,你是不是在偷懒啊,没有学习了。老哥,真的冤枉:我觉得我自己很菜,还在努力学习呢,正在学习Vue.js做管理系统呢。即便这样,我还是不...

Wenyi_Feng ⋅ 今天 ⋅ 0

博客迁移到 https://www.jianshu.com/u/aa501451a235

博客迁移到 https://www.jianshu.com/u/aa501451a235 本博客不再更新

为为02 ⋅ 今天 ⋅ 0

win10怎么彻底关闭自动更新

win10自带的更新每天都很多,每一次下载都要占用大量网络,而且安装要等得时间也蛮久的。 工具/原料 Win10 方法/步骤 单击左下角开始菜单点击设置图标进入设置界面 在设置窗口中输入“服务”...

阿K1225 ⋅ 今天 ⋅ 0

Elasticsearch 6.3.0 SQL功能使用案例分享

The best elasticsearch highlevel java rest api-----bboss Elasticsearch 6.3.0 官方新推出的SQL检索插件非常不错,本文一个实际案例来介绍其使用方法。 1.代码中的sql检索 @Testpu...

bboss ⋅ 今天 ⋅ 0

informix数据库在linux中的安装以及用java/c/c++访问

一、安装前准备 安装JDK(略) 到IBM官网上下载informix软件:iif.12.10.FC9DE.linux-x86_64.tar放在某个大家都可以访问的目录比如:/mypkg,并解压到该目录下。 我也放到了百度云和天翼云上...

wangxuwei ⋅ 今天 ⋅ 0

PHP语言系统ZBLOG或许无法重现月光博客的闪耀历史[图]

最近在写博客,希望通过自己努力打造一个优秀的教育类主题博客,名动江湖,但是问题来了,现在写博客还有前途吗?面对强大的自媒体站点围剿,还有信心和可能型吗? 至于程序部分,我选择了P...

原创小博客 ⋅ 今天 ⋅ 0

IntelliJ IDEA 2018.1新特性

工欲善其事必先利其器,如果有一款IDE可以让你更高效地专注于开发以及源码阅读,为什么不试一试? 本文转载自:netty技术内幕 3月27日,jetbrains正式发布期待已久的IntelliJ IDEA 2018.1,再...

Romane ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部