什么是IO
I/O 即输入Input/ 输出Output的缩写,其实就是计算机调度把各个存储中(包括内存和外部存储)的数据写入写出的过程;
- java中用“流(stream)”来抽象表示这么一个写入写出的功能,封装成一个“类”,都放在http://java.io这个包里面。
来理解“流”是什么?
通过“流”的形式允许java程序使用相同的方式来访问不同的输入/输出源。stream是从起源(source)到接收的(sink)的有序数据。我们这里把输入/输出源对比成“水桶”,那么流就是“管道”,这个“管道”的粗细、单向性等属性也就是区分了不同“流”的特性。
IO流的分类
可以从三个不同的维度进行分类:
1、按照流的方向(输出输入都是站在程序所在内存的角度划分的)
- 输入流:只能从中读取数据【主要由InputStream和Reader作为基类】
- 输出流:只能向其写入数据【主要由outputStream和Writer作为基类】
在下图中,从磁盘读取数据到内存是输入流,从client读取数据到server是输入流;同样,把内存数据写到磁盘是输出流,把server数据写到client是输出流
2、按照流的操作颗粒度划分
- 字节流:以字节为单元,可操作任何数据【主要由InputStream和outPutStream作为基类】
- 字符流:以字符为单元,只能操作纯字符数据,比较方便【主要由Reader和Writer作为基类】
3、按照流的角色划分
- 节点流:可以从/向一个特定的IO设备(如磁盘,网络)读/写数据的流,也叫【低级流,主要由】
- 处理流:用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能,也叫【高级流】
下图中可以看出来,处理流就是在基础的字节流上,进行了封装,增加了特定的功能,使得传输更适合特定的场景。
java中所有流汇总
http://java.io 中子类有40个“流”类,我们用以下表格来综合划分,当然这些流你不用都去花时间一个一个看过来,我们只要熟悉掌握几类常用的“流”就足够了,后续项目中如果用到陌生的“流”,知道原理的话可以快速地去检索学习下就ok了。
- File -- 文件类
- RandomAccessFile -- 随机存储文件类
- InputStream -- 字节输入流
- OutputStream -- 字节输出流
- Reader -- 字符输入流
- Writer -- 字符输出流
I/O 模型基本说明
- I/O 模型简单的理解:就是用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能。
- Java共支持3种网络编程模型/IO模式:BIO、NIO、AIO。
- Java BIO:同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销。
- Java NIO: 同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求就进行处理。
- Java AIO(NIO.2) :异步非阻塞,AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用。
BIO、NIO、AIO适用场景分析
-
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序简单易理解。
-
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,弹幕系统,服务器间通讯等。编程比较复杂,JDK1.4开始支持。
-
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
Java BIO
-
Java BIO 就是传统的java io 编程,其相关的类和接口在 java.io包下。
-
BIO(blocking I/O) : 同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善(实现多个客户连接服务器)。
-
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,程序简单易理解。
Java BIO 问题分析
-
每个请求都需要创建独立的线程,与对应的客户端进行数据 Read,业务处理,数据 Write 。
-
当并发数较大时,需要创建大量线程来处理连接,系统资源占用较大。
-
连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费。
Java NIO
JAVA NIO全称java non-blocking IO,是JDK提供的新API,从JDK1.4开始,java提供了一系列改进输入/输出的新特性,被称为NIO,是同步非阻塞的。
NIO相关类都被放在java.nio包下,并且对原来java.io包中有很多的类进行改写。
NIO有三大核心部分:Channel(通道),Buffer(缓冲区),Selector(选择器)。
NIO是面向缓冲区,或者面向块的编程,数据读取到一个稍后会处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用他可以提供非阻塞式的高伸缩性网络。
NIO 三大核心原理示意图
Selector 、 Channel 和 Buffer 的关系图(简单版)
关系图的说明:
-
每个channel 都会对应一个Buffer。
-
Selector 对应一个线程, 一个线程对应多个channel(连接)。
-
程序切换到哪个channel 是有事件决定的,Event 就是一个重要的概念。
-
Selector 会根据不同的事件,在各个通道上切换。
-
Buffer 就是一个内存块 , 底层是有一个数组。
-
数据的读取写入是通过Buffer,而BIO 中要么是输入流,或者是输出流,不能双向,但是NIO的Buffer 是可以读也可以写的,读写转换之前只需要调用 flip 方法切换即可。
-
channel 是双向的,可以返回底层操作系统的情况,比如Linux,底层的操作系统通道就是双向的。