`

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高级程序设计实战教程第五章-Java序列化机制.pptx

    5.2 相关知识 5.2.1 序列化的概念 5.2.2 序列化应用 5.2.3 序列化的几种方式 5.2.4 对象实现机制 Java高级程序设计实战教程第五章-Java序列化机制全文共15页,当前为第3页。 5.2.1 序列化的概念 将在内存中的各种...

    JAVA上百实例源码以及开源项目

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java 面试常见问题整理

    泛型 Java 泛型了解么?什么是类型擦除?介绍一下常用的通配符? 常用的通配符有哪些? 你的项目中哪里用到了泛型? 反射 何为反射?...Java 中 IO 流分为几种? 既然有了字节流,为什么还要有字符流?

    java开源包11

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包6

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包9

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包4

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包101

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包5

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包8

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包10

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    Java常见面试题208道.docx

    15.java 中 IO 流分为几种? 16.BIO、NIO、AIO 有什么区别? 17.Files的常用方法都有哪些? 二、容器 18.java 容器都有哪些? 19.Collection 和 Collections 有什么区别? 20.List、Set、Map 之间的区别是什么? 21....

    java开源包3

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    java开源包1

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

    Java 基础面试题

    该文档主要整理了常见的Java基础面试题,包含以下...31. 类加载有几种方式 32. Class.forName()和ClassLoader.loadClass()的区别 34. 如何防止创建的类名不能java为已有类名,Java加载双亲委派机制 35. 堆和栈的区别

    Java 2平台安全技术-结构,API设计和实现

    第2章 Java语言的基本安全特点 12 2.1 Java语言和平台 12 2.2 基本安全结构 13 2.3 字节代码验证和类型安全 14 2.4 签名应用小程序 15 2.5 关于安全错误及其修复的简要历史 16 第3章 JDK1.2安全结构 19 3.1 起源 19 ...

    java 面试题 总结

    assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为...

    java开源包2

    jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...

Global site tag (gtag.js) - Google Analytics