什么是NIO?

NIO 库是在 JDK 1.4 中引入的。NIO 弥补了原来的 I/O 的不足,它在标准 Java 代码中提供了高速的、面向块的 I/O。NIO翻译成 no-blocking io 或者 new io都说得通。

BIO的主要区别

面向流与面向缓冲

Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

阻塞与非阻塞IO

Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。

Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

选择器(Selectors)

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

NIO主要有三个核心部分组成:

buffer缓冲区、Channel管道、Selector选择器

Selector

Selector的英文含义是“选择器”,也可以称为为“轮询代理器”、“事件订阅器”、“channel容器管理机”都行。

应用程序将向Selector对象注册需要它关注的Channel,以及具体的某一个Channel会对哪些IO事件感兴趣。Selector中也会维护一个“已经注册的Channel”的容器。

Channels

通道,被建立的一个应用程序和操作系统交互事件、传递内容的渠道(注意是连接到操作系统)。那么既然是和操作系统进行内容的传递,那么说明应用程序可以通过通道读取数据,也可以通过通道向操作系统写数据,而且可以同时进行读写。

  • 所有被Selector(选择器)注册的通道,只能是继承了SelectableChannel类的子类。
  • ServerSocketChannel:应用服务器程序的监听通道。只有通过这个通道,应用程序才能向操作系统注册支持“多路复用IO”的端口监听。同时支持UDP协议和TCP协议。
  • ScoketChannel:TCP Socket套接字的监听通道,一个Socket套接字对应了一个客户端IP:端口 到 服务器IP:端口的通信连接。

通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

buffer缓冲区

本博客其他的随笔文章讲解

操作类型SelectionKey

在向Selector对象注册感兴趣的事件时,JAVA NIO共定义了四种作:OP_READ、OP_WRITE、OP_CONNECT、OP_ACCEPT(定义在SelectionKey中),分别对应读、写、请求连接、接受连接等网络Socket操作。

ServerSocketChannel和SocketChannel可以注册自己感兴趣的操作类型,当对应操作类型的就绪条件满足时OS会通知channel,下表描述各种Channel允许注册的操作类型,Y表示允许注册,N表示不允许注册,其中服务器SocketChannel指由服务器ServerSocketChannel.accept()返回的对象。

OP_READ

OP_WRITE

OP_CONNECT

OP_ACCEPT

服务器ServerSocketChannel

Y

服务器SocketChannel

Y

Y

客户端SocketChannel

Y

Y

Y

服务器启动ServerSocketChannel,关注OP_ACCEPT事件,

客户端启动SocketChannel,连接服务器,关注OP_CONNECT事件

服务器接受连接,启动一个服务器的SocketChannel,这个SocketChannel可以关注OP_READ、OP_WRITE事件,一般连接建立后会直接关注OP_READ事件

客户端这边的客户端SocketChannel发现连接建立后,可以关注OP_READ、OP_WRITE事件,一般是需要客户端需要发送数据了才关注OP_READ事件

连接建立后客户端与服务器端开始相互发送消息(读写),根据实际情况来关注OP_READ、OP_WRITE事件。

我们可以看看每个操作类型的就绪条件。

操作类型

就绪条件及说明

OP_READ

当操作系统读缓冲区有数据可读时就绪。并非时刻都有数据可读,所以一般需要注册该操作。

OP_WRITE

当操作系统写缓冲区有空闲空间时就绪。一般情况下写缓冲区都有空闲空间,小块数据直接写入即可,没必要注册该操作类型,否则该条件不断就绪浪费CPU;但如果是写密集型的任务,比如文件下载等,缓冲区很可能满,注册该操作类型就很有必要,同时注意写完后取消注册。

OP_CONNECT

当SocketChannel.connect()请求连接成功后就绪。该操作只给客户端使用。

OP_ACCEPT

当接收到一个客户端连接请求时就绪。该操作只给服务器使用。

原生JDK网络编程- NIO的更多相关文章

  1. 原生JDK网络编程- NIO之Reactor模式

    “反应”器名字中”反应“的由来: “反应”即“倒置”,“控制逆转”,具体事件处理程序不调用反应器,而向反应器注册一个事件处理器,表示自己对某些事件感兴趣,有时间来了,具体事件处理程序通过事件处理器对某 ...

  2. 原生JDK网络编程- Buffer

    Buffer用于和NIO通道进行交互.数据是从通道读入缓冲区,从缓冲区写入到通道中的.以写为例,应用程序都是将数据写入缓冲,再通过通道把缓冲的数据发送出去,读也是一样,数据总是先从通道读到缓冲,应用程 ...

  3. 原生JDK网络编程BIO

    服务端提供IP和监听端口,客户端通过连接操作想服务端监听的地址发起连接请求,通过三次握手连接,如果连接成功建立,双方就可以通过套接字进行通信. 传统的同步阻塞模型开发中,ServerSocket负责绑 ...

  4. Java网络编程 -- NIO非阻塞网络编程

    从Java1.4开始,为了替代Java IO和网络相关的API,提高程序的运行速度,Java提供了新的IO操作非阻塞的API即Java NIO.NIO中有三大核心组件:Buffer(缓冲区),Chan ...

  5. 网络编程NIO:BIO和NIO

    BIO BIO(Blocking I/O),同步阻塞,实现模式为一个连接一个线程,即当有客户端连接时,服务器端需为其单独分配一个线程,如果该连接不做任何操作就会造成不必要的线程开销.BIO是传统的Ja ...

  6. 网络编程NIO之Reactor线程模型

    目录 单Reactor线程模型 基于工作线程的Reactor线程模型 多Reactor线程模型 多Reactor线程模型示例 结束语 上篇文章中写了一些NIO相关的知识以及简单的NIO实现示例,但是示 ...

  7. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

  8. Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

    Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...

  9. Java网络编程与NIO详解2:JAVA NIO 一步步构建IO多路复用的请求模型

    本文转载自:https://github.com/jasonGeng88/blog 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 http ...

随机推荐

  1. Web接口测试理论知识分享

    首先谈下接口的定义分为2类,程序接口和协议接口 1.程序模块接口,具体到程序中就是提供了输入输出的类 方法,我们可以通过传入不同的参数,来验证程序接口的功能 2.协议接口  比如HTTP/SOAP协议 ...

  2. 2020-07-08:mysql只有一个表a,什么情况下会造成死锁,解决办法是什么?

    福哥答案2020-07-08: 表锁是不会出现死锁的,但锁等待现象是有可能的.行锁是行级别的,有可能出现死锁.环形等待死锁和唯一键死锁 很常见. 避免死锁方法:1.减少事务操作的记录数.2.约定按相同 ...

  3. Solon Ioc 的注解对比Spring及JSR330

    注解对比 Solon 1.0.10 Spring JSR 330 @XInject * @Autowired @Inject 字段或参数注入 @XBean * @Component @Named Be ...

  4. Java并发---并发理论

    一.如何理解线程安全 在多线程中稍微不注意就会出现线程安全问题,那么什么是线程安全问题? 我的认识是.在多线程下代码执行的结果和预期的正确的结果不一致,该代码就是线程不安全的,否则就是线程安全的 在深 ...

  5. 编译hotspot8

    编译hotspot8 ubuntu desktop 18 全新准备与编译过程再记录下: # 建议使用此gcc和g++版本,过高版本比如gcc7或引发编译报错 sudo apt-get install ...

  6. 编译原理根据项目集规范族构造LR(0)分析表

    转载于https://blog.csdn.net/Johan_Joe_King/article/details/79058597?utm_medium=distribute.pc_relevant.n ...

  7. 关于tomcat的一些基础知识

    tomcat的启动环境是要需要配置jdk的,本次示例用的是jdk1.8和tomcat 8.5. jdk环境变量配置可以在网上随意找到,这里就不再作示范了. 什么是Tomcat Tomcat简单的说就是 ...

  8. Golang bytes.buffer详解

    原文:https://www.jianshu.com/p/e53083132a25 Buffer 介绍 Buffer 是 bytes 包中的一个 type Buffer struct{…} A buf ...

  9. js实现将时分秒转化成毫秒,将秒转化成时分秒

    // 时间转为毫秒 timeToSec(time) { var hour = time.split('[0] var min = time.split('[1] var sec = time.spli ...

  10. Public-Key Cryptosystems Based on Composite Degree Residuosity Classes

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! 以下是对本文关键部分的摘抄翻译,详情请参见原文. 论文未全部翻译 Abstract. 本文研究了一个新的计算问题,即合数剩余阶问题(Com ...