`

JAVA几种IO工作机制及特点(二)

 
阅读更多

1.什么是IO?

1.1 什么是流?

 IO在本质上是单个字节的移动,而流可以说是字节移动的载体和方式,它不停的向目标处移动数据,我们要做的就是根据流的方向从流中读取数据或者向流中写入数据。最简单的Java流的例子就是下载电影,肯定不是等电影全部下载在内存中再保存到磁盘上,本质上是下载一个字节就保存一个字节。

  一个流,必有源和目标,它们可以是计算机内存的某些区域,也可以是磁盘文件,甚至可以是Internet上的某个URL。流的方向是重要的,根据流的方向,流可分为两类:输入流和输出流。我们从输入流读取数据,向输出流写入数据。

     Java传统的io是基于流的io即BIO(同步阻塞IO),从jdk1.4开始提供基于块的io,即nio即同步非阻塞IO,到jdk1.7之后出现aio 异步非阻塞IO。

 

1.2 IO分类

Java对io的支持主要集中在io包下,显然可以分为下面两类:

  1. 基于字节操作的io接口:InputStream 和 OutputStream

  2. 基于字符操作的io接口:Writer 和 Reader

不管磁盘还是网络传输,最小的存储单位都是字节,但是程序中操作的数据大多都是字符形式的,所以Java也提供了字符型的流。流并不等于io,还有很重要的一点,数据的传输方式,也就是数据写到哪里的问题,主要是以下两种:

  1. 基于磁盘操作的io接口:File

  2. 基于网络操作的io接口:Socket

 

到jdk1.4以后 出现socketChannel 管道,支持 select poll epoll等通讯方式。 

 

1.3 磁盘IO和网络IO工作机制

1.3.1 磁盘IO-file

io中数据写到何处也是重要的一点,其中最主要的就是将数据持久化到磁盘。数据在磁盘上最小的描述就是文件,上层应用对磁盘的读和写都是针对文件而言的在java中,以File类来表示文件,如:

 

File file = new File("D:/test.txt");

 

  但是严格来说,File并不表示一个真实的存在于磁盘上的文件。就像上面代码的文件其实并不存在,File做的只是根据你所提供的文件描述符,返回某一路径的虚拟对象,它并不关心文件或路径是否存在,可能存在,也可能是捏造的。就好象一张名片,名片的背后代表的是人。为什么要这么设计?

以FileInputStream读取文件为例,过程是这样的:当传入一个文件路径时,会根据这个路径创建File对象,作为这个文件的一个“名片”。当我们试图通过FileInputStream对象去操作文件的时候,将会真正创建一个关联真实存在的磁盘文件的文件描述符FileDescriptor,通过FileInputStream构造方法可以看出:

 

fd = new FileDescriptor(); 

 

  如果说File是文件的名片,那么FileDescriptor就是真正指向了一个打开的文件,可以操作磁盘文件。例如FileDescriptor.sync()方法可以将缓存中的数据强制刷新到磁盘文件中。如果我们需要读取的是字符,还需要通过StreamDecoder类将字节解码成字符。至于如何从物理磁盘上读取数据,那就是操作系统做的事情了。 

图 7. 从磁盘读取文件

1.3.2 网络io-socket

大部分情况下我们使用的都是基于TCP/IP协议的流Socket,因为它是一种稳定的通信协议。Socket就像一个插座,计算机通过Socket就能和网络或者其他计算机上进行通讯;当有数据通讯的需求时,只需要建立一个Socket“插座”,通过网卡与其他计算机相连获取数据。

  Socket位于传输层和应用层之间,向应用层统一提供编程接口,应用层不必知道传输层的协议细节。Java中对Socket的支持主要是以下两种:

  (1)基于TCP的Socket:提供给应用层可靠的流式数据服务,使用TCP的Socket应用程序协议:BGP,HTTP,FTP,TELNET等。优点:基于数据传输的可靠性。

  (2)基于UDP的Socket:适用于数据传输可靠性要求不高的场合。基于UDP的Socket应用程序协议:RIP,SNMP,L2TP等。

面向连接的套接字的系统调用时序图:

socket基本流程

无连接协议的套接字调用时序图
socket基本流程

 

1.4 为什么要使用NIO?

现在互联网提供的在线服务都是走网络I/O,那么对于网络I/O,传统的阻塞式I/O,一个线程对应一个连接,采用线程池的模式在大部分场景下简单高效。当有大量的连接的时候,我们可以为每一个连接建立一个线程来操作。但是这种做法带来的缺陷也是显而易见的:

  • 硬件能够支持大量的并发。

  • 并发的数量始终有一个上限。

  • 各个线程之间的优先级不好控制。

  • 各个Client之间的交互与同步困难。

我们也可以使用一个线程来处理所有的请求,使用不阻塞的IO,轮询查询所有的Client。这种做法同样也有缺陷:无法迅速响应Client端,同时会消耗大量轮询查询的时间。所以,我们需要一种poll的模式来处理这种情况,从大量的网络连接中找出来真正需要服务的Client。这正是NIO诞生的原因:提供一种Poll的模式,在所有的Client中找到需要服务的Client,现在支持epoll。JDK中,有一个非常有意思的库:NIO(New I/O)。这个库中有3个重要的类,分别是java.nio.channels中Selector和Channel,以及java.nio中的Buffer。

1.Channel代表一个可以被用于Poll操作的对象(可以是文件流/网络流),Channel能够被注册到一Selector中。

2.通过调用Selector的select方法可以从所有的Channel中找到需要服务的实例(Accept,read ..)。

3.Buffer对象提供读写数据的缓存。对于我们熟悉的Stream对象,Buffer提供更好的性能以及更好的编程透明性(人为控制缓存的大小以及具体的操作)。

 

 

2.BIO NIO AIO是什么,有什么特点?

这里主要讨论的是网络IO:

1.首先需要提到BIO中socket,这里面的阻塞点 accept 等待连接 ,read/write数据.

 

 

 

2.在说说NIO是中socketChannel   accept不会阻塞,而是交给一个线程去接收所有连接,将所有连接放到一个缓存队列上;最终会通过selector(可以看做是监听器)监听所有客户端的连接数据请求,会调用doselect()方法(阻塞点) 通知分发到(dispatch)到真正操作数据读写的业务线程池里,进行数据处理。

看看dubbo rpc的io处理机制:

 

3.阻塞/非阻塞,同步/异步 ?

3.1 阻塞(blocking)与非阻塞(non-blocking)IO

 

  IO的阻塞、非阻塞主要表现在一个IO操作过程中,如果有些操作很慢,比如读操作时需要准备数据,那么当前IO进程是否等待操作完成,还是得知暂时不能操作后先去做别的事情?一直等待下去,什么事也不做直到完成,这就是阻塞。抽空做些别的事情,这是非阻塞。

  非阻塞IO会在发出IO请求后立即得到回应,即使数据包没有准备好,也会返回一个错误标识,使得操作进程不会阻塞在那里。操作进程会通过多次请求的方式直到数据准备好,返回成功的标识。

 

3.2同步(synchronous)与异步(asynchronous)IO

  先来看看正式点的定义,POSIX标准将IO模型分为了两种:同步IO和异步IO,Richard Stevens在《Unix网络编程卷》中也总结道:

 

A synchronous I/O operation causes the requesting process to be blocked until that I/O operationcompletes;An asynchronous I/O operation does not cause the requesting process to be blocked;

 

  可以看出,判断同步和异步的标准在于:一个IO操作直到完成,是否导致程序进程的阻塞。如果阻塞就是同步的,没有阻塞就是异步的。这里的IO操作指的是真实的IO操作,也就是数据从内核拷贝到系统进程(读)的过程。

 

 

 

参考:

1.细说JAVA IO

2.IO阻塞与非阻塞

分享到:
评论

相关推荐

    java io 与java nio区别

    它主要包括以下几种核心类: - `InputStream`/`OutputStream` - `Reader`/`Writer` 这些类提供了一系列用于读写文件、网络数据等的基础方法。在Java IO模型中,当一个线程发起一个IO操作请求时,该线程会一直阻塞...

    Java,彻底明白Java语言中的IO系统

    Java IO系统提供了以下几种转换流: - `InputStreamReader`:将字节流转换为字符流。 - `OutputStreamWriter`:将字符流转换为字节流。 #### 6. 过滤器流 过滤器流是在原有流的基础上添加额外功能的流,它可以对...

    Java 的 IO流笔记.md

    Java的IO流体系主要包括以下几种流: - **FileInputStream/FileOutputStream**:节点流,用于以字节为单位直接操作文件。 - **ByteArrayInputStream/ByteArrayOutputStream**:节点流,用于以字节为单位直接操作...

    java全栈工程师-java io

    ### 常见几种IO操作 #### 1. 文件IO - **FileInputStream/FileOutputStream**:用于处理文件的字节流读写。 - **FileReader/FileWriter**:用于处理文件的字符流读写。 - **BufferedReader/BufferedWriter**:提供...

    Java基于IO流读取文件的方法

    在Java编程中,IO流(Input/Output Stream)是处理数据输入与输出的核心机制。Java IO流分为字符流和字节流,适用于不同类型的文件和数据源。本文将深入探讨如何使用IO流来读取文件,并通过实例代码详细解释每一个...

    Java IO, NIO and NIO.2

    Java IO、NIO以及NIO.2是Java中用于处理输入/输出操作的三种主要机制。本书《Java IO, NIO and NIO.2》旨在深入浅出地介绍这些机制,同时书中内容均为英文。接下来将详细介绍这些知识点。 **Java IO** Java IO是...

    java io流-3.pdf

    - **6.2 过滤流子类**:具体介绍了几种常见的过滤流子类,如`BufferedInputStream`、`BufferedOutputStream`等。 - **6.3 缓冲流**:通过增加缓存机制提高读写效率。 - **6.4 PushbackInputStream**:允许数据回退到...

    基于java的异步IO框架 Cindy.zip

    在Java标准库中,NIO(New IO)提供了一种异步I/O操作的机制。传统的Java IO基于阻塞I/O模型,即在读写操作时,线程会被阻塞直到数据传输完成。而NIO引入了选择器(Selector)和通道(Channel)的概念,使得一个线程...

    Java IO 性能优化

    为了提高序列化性能,可以采取以下几种策略: 1. **使用自定义序列化逻辑**:通过实现`Serializable`接口的子接口`Externalizable`,可以控制对象的序列化和反序列化过程。这样可以在序列化过程中省略不必要的字段...

    完整版Java全套入门培训课件 Java基础 07-IO(共29页).pptx

    Java IO(InputOutput)是Java平台中用于处理设备间数据传输的重要部分,它提供了一种在程序和外部数据源之间传输数据的机制。Java中的所有IO操作都是通过流(Stream)来实现的,这些流的对象主要集中在java.io包中...

    java2年工作经验简历_java简历.doc

    4. **IO流与NIO**:熟练使用Java的输入输出流进行文件操作,理解流的分类和工作原理。对Java NIO(New IO)有一定的了解,知道它如何提高IO操作的效率。 5. **多线程**:掌握线程的创建和管理,理解同步机制,如...

    Scalable IO in Java

    NIO是一种基于通道(Channel)和缓冲区(Buffer)进行IO操作的机制,与传统的阻塞式IO相比,NIO能够提供更好的性能和扩展性,特别是在处理大量并发连接时。 文档内容提到了以下几个关键点: 1. 可扩展网络服务:这...

    javaSE 关于IO几种读取方式的性能比较

    Java提供了多种读取二进制数据的方式,最常用的是`java.io.InputStream`及其子类,如`FileInputStream`。`InputStream`家族适用于处理任何类型的原始字节流,不关心数据的含义或编码。例如,当我们需要读取图片、...

    java学习笔记(java 反射机制 流 内存管理)

    JVM提供了几种不同的垃圾收集算法,如标记-清除、复制、标记-整理和分代收集。内存泄露是常见的问题,当不再使用的对象仍然被引用,无法被垃圾收集器回收。此外,栈内存用于存储方法局部变量,随着方法的调用和返回...

    java sdk01.rar_io_java 类库

    `java.io`包的基本概念主要包括以下几点: 1. **流(Stream)**:在Java中,输入输出操作是通过流来完成的。流是一种抽象的数据通道,可以用于传输不同类型的数据(如字符或字节)。流可以分为两类:输入流(Input ...

    自己封装的IO核NIO

    "自己封装的IO核NIO"项目的目标就是将这两种IO模型进行抽象和封装,以提供更简洁、易用的API。开发者无需关心底层细节,只需调用几个简单的接口就能完成数据的读写和网络通信,大大降低了使用难度。 在这个基础上,...

    2021最新Java面试题及答案V2.0.pdf

    在Java面试中,考官通常会询问Java基础知识、Java集合框架、Java虚拟机(JVM)、Java IO/NIO、Java类加载机制等方面的知识点。本文将基于提供的文件内容,详细解释这些知识点。 首先,JVM(Java Virtual Machine)...

    java类加载机制原理与实现

    双亲委派机制是 Java 中的一种类加载机制,用于解决类加载器之间的关系。其工作原理是:当一个类加载器需要加载某个类时,首先将请求委派给其父加载器,如果父加载器可以加载该类,则由父加载器加载,否则继续委派给...

Global site tag (gtag.js) - Google Analytics