上文我们描述了五中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提供了SocketChannelServerSocketChannel ,这两个新增的通道都支持阻塞和非阻塞模式,阻塞模式使用简单,但是性能和可靠性都不好。非阻塞模式则相反。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 简介的更多相关文章

  1. JAVA NIO 简介(转)

    1.   基本 概念 IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. 所有语言运行时系统提供执行 I/O 较高级 ...

  2. JAVA NIO学习一:NIO简介、NIO&IO的主要区别

    在前面学习了IO之后,今天我们开始进入NIO学习环节,首先我们会NIO做一个简单的介绍,让大家认识NIO,然后会和IO进行一个对比认识进行区分.好了,下面我们就开始学习: 一.NIO简介 1.概述 从 ...

  3. Java NIO系列教程(一)java NIO简介

    这个系列的文章,我们开始玩一玩IO方面的知识,对于IO和NIO,我们经常会接触到,了解他们的基本内容,对于我们的工作会有特别大的帮助.这篇博文我们仅仅是介绍IO和NIO的基本概念,以及一些关键词. 基 ...

  4. JAVA NIO 简介 (netty源码死磕1.1)

    [基础篇]netty 源码死磕1.1:  JAVA NIO简介 1. JAVA NIO简介 Java 中 New I/O类库 是由 Java 1.4 引进的异步 IO.由于之前老的I/O类库是阻塞I/ ...

  5. java NIO简介

    1)java nio简介 nio 是 java New IO 的简称,在 jdk1.4 里提供的新 api . Sun 官方标榜的特性如有:为所有的原始类型提供 (Buffer) 缓存支持:字符集编码 ...

  6. (一:NIO系列)JAVA NIO 简介

    出处:JAVA NIO 简介 Java 中 New I/O类库 是由 Java 1.4 引进的异步 IO.由于之前老的I/O类库是阻塞I/O,New I/O类库的目标就是要让Java支持非阻塞I/O, ...

  7. JAVA NIO简介-- Buffer、Channel、Charset 、直接缓冲区、分散和聚集、文件锁

    IO  是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. Java标准io回顾 在Java1.4之前的I/O系统中,提供 ...

  8. nio简介

    上一篇  Java I/O演进与Linux网络I/O模型 一.传统BIO java传统bio编程概念: http://www.cnblogs.com/carl10086/p/6034563.html# ...

  9. Java IO流-NIO简介

    2017-11-05 22:09:04 NIO NIO:new IO就是新IO的意思,JDK4开始出现新IO,新IO和传统的IO有相同的目的,都是用于进行输入输出的,但是新IO使用了不同的方式来处理输 ...

随机推荐

  1. CentOS7 VMware-Tools安装与共享文件夹设置

    一. VMware-Tools安装 1.加载VMware Tools的光驱:点击"虚拟机"->"安装VMware Tools".这里,由于我已经安装了,所 ...

  2. PHP常用日期加减计算方法实例

    PHP常用日期加减计算方法实例 实例总结了PHP常用日期加减计算方法.分享给大家供大家参考,具体如下: PHP 标准的日期格式 date("Y-m-d H:i:s"); PHP 简 ...

  3. String.matches()的用法

    https://blog.csdn.net/victoryckl/article/details/6930409

  4. MyBatis 缓存机制

    Mybatis 有两级缓存: 一级缓存: 也称为本地缓存,SqlSession级别的缓存.一级缓存是一直开启的: 与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从 ...

  5. 在浏览器输入URL时发生了什么

    浏览器器检查cache,如果请求对象已经缓存并且是最新的,执行第9步. 浏览器询问操作系统,请求服务器的IP地址 操作系统进行DNS查找,然后告诉浏览器服务器的IP 浏览器和服务器简历一个TCP连接( ...

  6. node07

    ---恢复内容开始--- 1.SQL基本查询语句 2.子句 1)WHERE 子句 WHERE key=val WHERE key>val WHERE key1>val1 AND key2& ...

  7. react-quill 富文本编辑器 ---- 图片处理

    import React,{Component} from 'react'; import ReactQuill,{ Quill } from 'react-quill'; import 'react ...

  8. java实现注册的短信验证码

    最近在做只能净化器的后台用户管理系统,需要使用手机号进行注册,找了许久才大致了解了手机验证码实现流程,今天在此和大家分享一下. 我们使用的是榛子云短信平台, 官网地址:http://smsow.zhe ...

  9. Where is the Marble? (寻找大理石上的数字)

    (先上题目) (题目描述)Raju and Meena love to play with Marbles. They have got a lot of marbles with numbers w ...

  10. MemCache详细解读

    MemCache是什么 MemCache是一个自由.源码开放.高性能.分布式的分布式内存对象缓存系统,用于动态Web应用以减轻数据库的负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高 ...