NIO:新IO,同步的非阻塞IO。

1.Java NIO 由以下几个核心部分组成:Channels(通道)、Buffers(缓冲区)、Selectors(选择器)

Channels(通道)

1.所有的 IO 在NIO 中都从一个Channel 开始。

Channel用来读取和写入数据,类似于之前的输入流/输出流。

Channel通道是双向的,通过一个Channel既可以进行读,也可以进行写;而Stream只能进行单向操作,通过一个Stream只能进行读

一般不会直接操作通道,内容都是先读到或者写入到Buffers,再通过Buffers完成读写。

Buffer(缓冲区)

1.Buffer可以分为ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer

2.Buffer中有几个状态变量:

  • position: Buffer读取或写入的下一个操作指针,当向Buffer写入数据时此指针会改变,放在写入的最后一个元素之后。比如Buffer中写入了4个位置的数据,则position会指向第五个位置。
  • limit: 在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。写模式下,limit等于Buffer的capacity。
            当读模式时, limit表示你最多能读到多少数据。
  • capacity: 表示Buffer的最大容量,limit<=capacity。此值在分配Buffer时被设置,一般不会更改。

3.Buffer中的常用方法:

ByteBuffer.allocate(数量) : 开辟缓存区,初始化大小

flip()  :此方法将position设置为0,limit放到position位置。用于重设缓存区,以便接下来的输入输出。

get() :取出当前position的内容

put(): 在buffer里面写入内容

示例如下:

使用FileChannel配合Buffer读取文件,如下所示:

public class FileChannelRead {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream=new FileInputStream(new File("E:\\test2.txt"));
FileChannel fileChannel=fileInputStream.getChannel();
//初始化缓冲区大小
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
//将文件通道里面的字节读到缓冲区中
fileChannel.read(byteBuffer);
//此方法将position置为0,limit放到position位置
byteBuffer.flip();
// position<limit时返回true,用于判断是否还有数据。
while (byteBuffer.hasRemaining()) {
//读取缓冲区Buffer里面的内容
System.out.print((char)byteBuffer.get());
}
fileChannel.close();
}
}

使用FileChannel配合Buffer写入文件,如下所示:

public class FileChannelWrite {

    public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream=new FileOutputStream(new File("E:\\test2.txt"),true);
//获取输出的fileChannel(文件通道)
FileChannel fileChannel= fileOutputStream.getChannel();
//开辟缓冲
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
String name="lin";
//向缓冲区写入数据
byteBuffer.put(name.getBytes());
//重设缓冲区,准备输出
byteBuffer.flip();
//写入内容
fileChannel.write(byteBuffer);
fileChannel.close();
fileOutputStream.close();
System.out.println("写入成功");
}
}

Selector(选择器)

1.Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。

仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。

使用Selector配合ServerSocketChannel,进行网络操作,示例如下:

/**
* 创建一个非阻塞的服务器,向客户端返回当前的系统时间
*/
public class SelectorDemo {
public static void main(String[] args) throws IOException {
int ports[]= { 8000,8001,8002,8003,8004 } ;
Selector selector=Selector.open();
for(int port : ports) {
//打开服务器套接字通道
ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();
//服务器配置设置为非阻塞
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket=serverSocketChannel.socket();
InetSocketAddress inetSocketAddress=new InetSocketAddress(port);
serverSocket.bind(inetSocketAddress);
//注册选择器,相当于使用accept()方法接收
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT );
System.out.println("服务器运行,在"+port+"端口监听");
} int keysAdd;
//选择一组键,相当的通道已为IO准备就绪
while ( (keysAdd=selector.select())>0 ) {
//取出全部生成的key
Set<SelectionKey> selectionKeySet=selector.selectedKeys() ;
Iterator<SelectionKey> iterator=selectionKeySet.iterator();
//迭代全部的SelectionKey
while (iterator.hasNext()) {
SelectionKey key=(SelectionKey) iterator.next();
//判断客户端是否已经连接上
if(key.isAcceptable()) {
//通过key获取channel
ServerSocketChannel serverSocketChannel=(ServerSocketChannel) key.channel();
SocketChannel socketChannel=serverSocketChannel.accept();
serverSocketChannel.configureBlocking(false);
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
byteBuffer.put(( "当前时间为"+new Date() ).getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer);
socketChannel.close();
}
}
selectionKeySet.clear();
}
}
}

IO和NIO的区别:

  • IO是多线程的,阻塞的。NIO,是同步的非阻塞IO。
  • IO面向Stream(流),而NIO面向Buffer(缓冲区)
  • IO是多个线程的,不存在Selector。而Java NIO的Selector(选择器)允许一个单独的线程来监视多个Channel(输入通道)

代码示例见GitHub:

https://github.com/firefoxer1992/JavaDemo/tree/master/src/main/java/com/nio

参考资料:http://ifeve.com/java-nio-all/

NIO简单理解的更多相关文章

  1. git的简单理解及基础操作命令

    前端小白一枚,最近开始使用git,于是花了2天看了廖雪峰的git教程(偏实践,对于学习git的基础操作很有帮助哦),也在看<git版本控制管理>这本书(偏理论,内容完善,很不错),针对所学 ...

  2. 简单理解Struts2中拦截器与过滤器的区别及执行顺序

    简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...

  3. [转]简单理解Socket

    简单理解Socket 转自 http://www.cnblogs.com/dolphinX/p/3460545.html  题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公 ...

  4. Js 职责链模式 简单理解

    js 职责链模式 的简单理解.大叔的代码太高深了,不好理解. function Handler(s) { this.successor = s || null; this.handle = funct ...

  5. Deep learning:四十六(DropConnect简单理解)

    和maxout(maxout简单理解)一样,DropConnect也是在ICML2013上发表的,同样也是为了提高Deep Network的泛化能力的,两者都号称是对Dropout(Dropout简单 ...

  6. Deep learning:四十二(Denoise Autoencoder简单理解)

    前言: 当采用无监督的方法分层预训练深度网络的权值时,为了学习到较鲁棒的特征,可以在网络的可视层(即数据的输入层)引入随机噪声,这种方法称为Denoise Autoencoder(简称dAE),由Be ...

  7. 简单理解dropout

    dropout是CNN(卷积神经网络)中的一个trick,能防止过拟合. 关于dropout的详细内容,还是看论文原文好了: Hinton, G. E., et al. (2012). "I ...

  8. 我们为之奋斗过的C#-----C#的一个简单理解

    我们首先来简单叙述一下什么是.NET,以及C#的一个简单理解和他们俩的一个区别. 1 .NET概述 .NET是Microsoft.NET的简称,是基于Windows平台的一种技术.它包含了能在.NET ...

  9. 简单理解ECMAScript2015中的箭头函数新特性

    箭头函数(Arrow functions),是ECMAScript2015中新加的特性,它的产生,主要有以下两个原因:一是使得函数表达式(匿名函数)有更简洁的语法,二是它拥有词法作用域的this值,也 ...

随机推荐

  1. 使用mondorescue将本机linux centos 7服务器制作成光盘

    https://blog.csdn.net/wuxianfeng1987/article/details/78059618   没试 重新封装linux系统成iso文件 https://zhidao. ...

  2. 作为sort()方法的参数的比较函数(高程三第五章)

    <script> var nums = [0,1,5,10,15]; var nums2 = nums; nums.sort(); console.log(nums);//0,1,10,1 ...

  3. Retrofit添加自定义转换器

    Retrofit2开始支持多种 Converter 并存,在之前,如果你遇到这种情况:一个 API 请求返回的结果需要通过 JSON 反序列化,另一个 API 请求需要通过 proto 反序列化,唯一 ...

  4. 远程桌面连接MySQL遇到的问题及解决方法总结

    背景提要:想用Delphi做一个可以连接Mysql数据库的桌面应用程序.其中遇到了一些让自己很苦恼的问题.因为自己是新手,Delphi用的不熟,FireDAC这个连接数据库里控件更是没有接触过,对安装 ...

  5. ThinkPHP输入验证和I方法使用

    在Web开发过程中,我们经常需要获取系统变量或者用户提交的数据,这些变量数据错综复杂,而且一不小心就容易引起安全隐患,但是如果利用好ThinkPHP提供的变量获取功能,就可以轻松的获取和驾驭变量了. ...

  6. Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  7. 【Linux】CentOS7 安装,遇到的各种问题,并修复win7启动项

    https://www.cnblogs.com/sxdcgaq8080/p/7457255.html ------------------------------------------------- ...

  8. C# 调用 C++ 的 DLL 返回值为 bool 时,值混乱

    现象:C++ 导出函数的返回值为 false,C# 调用该函数获取的返回值却为 true . 原因:C++ 导出函数返回 false 时,采取的方式是: 将 C# 定义的用来接收返回值的 bool 所 ...

  9. mysqldump: Got error: 1066: Not unique table/alias

    mysqldump: Got error: 1066: Not unique table/alias myql 导出时提示如下: [root@localhost mysql]# mysqldump  ...

  10. eclipse 导出 javadoc

    项目右键Export ->java/javadoc -> 选择要导出的项目,javadoc.exe,存放路径,导出的级别(private可导出全部) ->在VM option中加入- ...