NIO 简介
上文我们描述了五中IO类型。第一种同步阻塞模型我们我们称之为BIO(Blocking IO),
第三种IO复用模型我们称之为NIO(Nonblocking IO)。
上图我们可以很容易的发现 BIO会为每个socket请求创建一个线程,而NIO可以通过一个线程处理多个请求。当然,我们可以为BIO构建一个线程池,这是一种伪异步的BIO模型。BIO和NIO最大的区别还是在阻塞上面。
阻塞主要有两方面
- 等待网络可读写
server.accept()
- 读写阻塞
通过观察InputStream的Api我们可以了解到,只有在下面三种情况下,BIO才会解除阻塞
1.有数据可读
2.可用数据已读取完毕
3.发送空指针或者I/O异常
所以,假如我们使用BIO进行网络消息传递,在网络不稳定的情况下,一次消息的传递需要花费30s,那这个bio的线程就需要阻塞30秒,假如所有的线程都阻塞30s,那系统基本就不可用了。
基于上述的问题,java推出了NIO。我们先用一段代码看看NIO的编程
public static void main(String[] args) throws Exception {
// 打开一个ServerSocketChannel
ServerSocketChannel socketChannel = ServerSocketChannel.open();
socketChannel.configureBlocking(Boolean.FALSE);
// 获取ServerSocketChannel绑定的Socket
ServerSocket socket = socketChannel.socket();
// 设置ServerSocket监听的端口
socket.bind(new InetSocketAddress(PORT));
System.out.println("开始等待客户端连接");
// 打开一个选择器
Selector selector = Selector.open();
// 将ServerSocketChannel注册到选择器上去并监听accept事件
socketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 这里会发生阻塞,等待就绪的通道
int select = selector.select();
// 没有就绪的通道则什么也不做
if (select == 0) {
continue;
}
// 获取SelectionKeys上已经就绪的通道的集合
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
// 遍历每一个Key
while (iterator.hasNext()){
SelectionKey next = iterator.next();
if (next.isAcceptable()){
ServerSocketChannel channel = (ServerSocketChannel) next.channel();
SocketChannel socketChannel1 = channel.accept();
socketChannel1.register(selector,SelectionKey.OP_READ);
}else if (next.isReadable()){
readDataFromSocket(next);
}
iterator.remove();
}
}
}
private static ByteBuffer bb = ByteBuffer.allocate(1024);
private static void readDataFromSocket(SelectionKey next) throws IOException {
SocketChannel sc = (SocketChannel)next.channel();
bb.clear();
while (sc.read(bb)>0){
bb.flip();//
//告知在当前位置和限制之间是否有元素
while (bb.hasRemaining()){
System.out.println((char) bb.get());
}
System.out.println();
bb.clear();
}
}
java为NIO提供了全新的API,大致有以下三种
- 缓冲区 Buffer
一个缓冲区对象是固定数量的数据的容器,其作用是一个存储器,或者分段运输区,在这里数据可被存储并在之后用于检索。从数据结构而言,缓冲区就是一个数组,通常是一个字节数组即ByteBuffer。每一种java基本类型都有对应的缓冲区
- Channel
与socket类和SeverSocket类似。NIO提供了SocketChannel和ServerSocketChannel ,这两个新增的通道都支持阻塞和非阻塞模式,阻塞模式使用简单,但是性能和可靠性都不好。非阻塞模式则相反。Channel可以自由的设置阻塞对Java来说意义非常重大。试想下之前的BIO网络编程为什么一个连接必须要对应一个线程。由于NIO的channel可以设置非阻塞模式,我们完全可以通过一个线程接受多个socket请求。
有两点需要我们注意:
1.文件通道总是阻塞的,不能设置成非阻塞模式
2.Channel只能往Buffer中写入
- Selector
选择器的作用是协调管理多个channel,selector定义了4种channel事件,每次channel注册的时候都必须定义好自己关心的是哪一种事件。注册完成后selector会一直阻塞,直到某些事件就绪。
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;
在了解上述三个api之后,我们再简单分析下上述代码
1.创建ServerSocketChannel
2.设置ServerSocketChannel为非阻塞状态
3.监听端口
4.将ServerSocketChannel 注册到一个Selector
5.等待选择接受就绪事件,一旦接收到 即可做出相应的操作
NIO的阻塞
如上图所示,NIO其实是有阻塞的环节的。那为什么我们仍然称NIO是同步非阻塞IO呢。这里主要涉及到一次完整的io请求是怎么进行读写的。
所有的系统I/O都分为两个阶段:
等待就绪和操作。举例来说,读函数,分为等待系统可读和真正的读;同理,写函数分为等待网卡可以写和真正的写。等待就绪的阻塞是不使用CPU的,是在“空等”;而真正的读写操作的阻塞是使用CPU的,真正在"干活",而且这个过程非常快,属于memory copy,带宽通常在1GB/s级别以上,可以理解为基本不耗时。
对于BIO而言,如果TCP RecvBuffer里没有数据,函数会一直阻塞,直到收到数据,再阻塞的读到的数据。
对于NIO,如果TCP RecvBuffer有数据,就把数据从网卡读到内存,并且返回给用户;反之则直接返回0,永远不会阻塞。
所以,socket主要的读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,真正的I/O操作是同步阻塞的(消耗CPU但性能非常高)。这部分的阻塞相对于BIO而言,是可以忽略不计的。所以我们可以认为NIO是非阻塞的。
NIO 简介的更多相关文章
- JAVA NIO 简介(转)
1. 基本 概念 IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. 所有语言运行时系统提供执行 I/O 较高级 ...
- JAVA NIO学习一:NIO简介、NIO&IO的主要区别
在前面学习了IO之后,今天我们开始进入NIO学习环节,首先我们会NIO做一个简单的介绍,让大家认识NIO,然后会和IO进行一个对比认识进行区分.好了,下面我们就开始学习: 一.NIO简介 1.概述 从 ...
- Java NIO系列教程(一)java NIO简介
这个系列的文章,我们开始玩一玩IO方面的知识,对于IO和NIO,我们经常会接触到,了解他们的基本内容,对于我们的工作会有特别大的帮助.这篇博文我们仅仅是介绍IO和NIO的基本概念,以及一些关键词. 基 ...
- JAVA NIO 简介 (netty源码死磕1.1)
[基础篇]netty 源码死磕1.1: JAVA NIO简介 1. JAVA NIO简介 Java 中 New I/O类库 是由 Java 1.4 引进的异步 IO.由于之前老的I/O类库是阻塞I/ ...
- java NIO简介
1)java nio简介 nio 是 java New IO 的简称,在 jdk1.4 里提供的新 api . Sun 官方标榜的特性如有:为所有的原始类型提供 (Buffer) 缓存支持:字符集编码 ...
- (一:NIO系列)JAVA NIO 简介
出处:JAVA NIO 简介 Java 中 New I/O类库 是由 Java 1.4 引进的异步 IO.由于之前老的I/O类库是阻塞I/O,New I/O类库的目标就是要让Java支持非阻塞I/O, ...
- JAVA NIO简介-- Buffer、Channel、Charset 、直接缓冲区、分散和聚集、文件锁
IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. Java标准io回顾 在Java1.4之前的I/O系统中,提供 ...
- nio简介
上一篇 Java I/O演进与Linux网络I/O模型 一.传统BIO java传统bio编程概念: http://www.cnblogs.com/carl10086/p/6034563.html# ...
- Java IO流-NIO简介
2017-11-05 22:09:04 NIO NIO:new IO就是新IO的意思,JDK4开始出现新IO,新IO和传统的IO有相同的目的,都是用于进行输入输出的,但是新IO使用了不同的方式来处理输 ...
随机推荐
- 【C语言编程练习】5.7填数字游戏求解
之前的东西就不上传了,大致就跟现在的一样 1. 题目要求 计算 ABCD * E DCBA 这个算式中每个字母代表什么数字? 2. 题目分析 如果是我们人去做这道题会怎么办,一定是这样想把,一个四位 ...
- CentOS7 VMware-Tools安装与共享文件夹设置
一. VMware-Tools安装 1.加载VMware Tools的光驱:点击"虚拟机"->"安装VMware Tools".这里,由于我已经安装了,所 ...
- IIS 接口访问404
IIS->网站->ASP->启用父路径(true)
- VS Code 常用插件
1.Chinese (Simplified) Language Pack for Visual Studio Code VS Code软件汉化 2.Auto Close Ta ...
- [LeetCode] Minimum Cost to Merge Stones 混合石子的最小花费
There are N piles of stones arranged in a row. The i-th pile has stones[i] stones. A move consists ...
- 【原创】XAF 常见错误以及对应解决方法
1.Appearance Criteria设置错误 Exception occurs while assigning the 'DetailView, ID:xxx_DetailView' view ...
- Fence Repair POJ - 3253 (贪心)
Farmer John wants to repair a small length of the fence around the pasture. He measures the fence an ...
- Mybatis Mapper文件中的一小坑
前几天来一需求,实现过程中需要修改一个底层的查询接口,具体修改就是在where中添加一个条件,由于这个底层SQL使用的地方太多,所以就想着是用if加一标识符做个判断,传一个只有我会使用的参数,然后动态 ...
- python+SQLAlchemy+爬虫
python+SQLAlchemy+爬虫 前面分享了SQLAlchemy的知识,这次我共享一下学习用python开发爬虫再把爬出来的数据放到用SQLAlchemy的数据库上面的知识,当然我这个是带测试 ...
- Java script 逻辑运算符
a && b : 将a, b转换为Boolean类型, 再执行逻辑与, true返回b, false返回a 1.只要“&&”前面是false,无论“&& ...