IO流和NIO

本文详细介绍了Java的IO流和NIO(非阻塞I/O)的区别,包括阻塞I/O的工作原理和非阻塞I/O的优势。NIO的核心组件包括Channel、Buffer和Selector,通过Selector可以监听多个通道的事件,实现单线程管理多个连接。文章还阐述了FileChannel、SocketChannel、ServerSocketChannel和DatagramChannel的使用,以及Selector的注册、选择和管理键的方法。
摘要由CSDN通过智能技术生成

IO请求底层流程

为了OS的安全性等的考虑,进程是无法直接操作I/O设备的,其必须通过系统调用请求内核来协助完成I/O动作,而内核会为每个I/O设备维护一个buffer。
如下图所示:
在这里插入图片描述
整个请求过程为: 用户进程发起请求,内核接受到请求后,从I/O设备中获取数据到buffer中,再将buffer中的数据copy到用户进程的地址空间,该用户进程获取到数据后再响应客户端。
在整个请求过程中,数据输入至buffer需要时间,而从buffer复制数据至进程也需要时间。

记住这两点很重要

1 等待数据准备 (Waiting for the data to be ready)
2 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)

阻塞I/O (Blocking I/O)

在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:

当用户进程调用了某个系统调用,内核就开始了IO的第一个阶段:等待数据准备。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候内核就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当内核一直等到数据准备好了,它就会将数据从内核中拷贝到用户内存,然后内核返回结果,用户进程才解除block的状态,重新运行起来。
所以,blocking IO的特点就是在IO执行的两个阶段都被block了。

非阻塞I/O (Non-Blocking I/O)

linux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:

当用户进程调用某个系统调用时,系统不会阻塞用户进程,而是立刻返回一个ewouldblock错误,从用户进程角度讲 ,并不需要等待,而是马上就得到了一个结果。用户进程判断标志是ewouldblock时,就知道数据还没准备好,于是它就可以去做其他的事了,于是它可以再次发送IO请求,一旦内核中的数据准备好了。并且又再次收到了用户进程的请求,那么它马上就将数据拷贝到了用户内存,然后返回。

IO概念

io流分为输入流及输出流,输入流是文件到内存,输出流是内存到文件。
输入流:把能够读取一个字节序列的对象称为输入流
输出流:把能够写一个字节序列的对象称为输出流
输入输出是相对于内存设备而言的,将外设(硬盘,键盘等)中的数据读取到内存设备
中叫输入;将内存设备中的数据写入到外设中叫输出,所以有读入,写出的称呼:读入到内
存,写出内存。
可以这样比喻:输入流和输出流中间连接着内存,输入流和输出流将读写分离开来进
行操作,先从外设读入内存,然后再写出内存转移到其他外设。

NIO

概念

NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

NIO和传统IO(一下简称IO)之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区。

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

Channel

Channel和传统IO中的Stream很相似。虽然很相似,但是有很大的区别,主要区别为:通道是双向的,通过一个Channel既可以进行读,也可以进行写;而Stream只能进行单向操作,通过一个Stream只能进行读或者写。
以下是常用的几种通道

  • FileChannel 通过使用FileChannel可以从文件读或者向文件写入数据,只能使用阻塞模式运行;
  • SocketChanel 通过SocketChannel,以TCP来向网络连接的两端读写数据;
  • ServerSocketChannel 通过ServerSocketChanel能够监听客户端发起的TCP连接,并为每个TCP连接创建一个新的SocketChannel来进行数据读写;
  • DatagramChannel 通过DatagramChannel,以UDP协议来向网络连接的两端读写数据。

FileChannel

Java NIO FileChannel是连接到文件的通道。使用FileChannel,可以从文件中读取数据,并将数据写入文件。 Java NIO FileChannel类是标准Java IO API读取文件的可替代方法。
FileChannel不能设置为非阻塞模式,它只能使用阻塞模式运行

    //1.打开一个文件通道(FileChannel)需要通过InputStream,OutputStream或RandomAccessFile获取FileChannel。 以下是通过RandomAccessFile打开FileChannel的方法ÿ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值