I/O模型

在开始NIO的学习之前,先对I/O的模型有一个理解,这对NIO的学习是绝对有好处的。我画一张图,简单表示一下数据从外部磁盘向运行中进程的内存区域移动的过程:

这张图片明显忽略了很多细节,只涉及了基本操作,下面分析一下这张图。

用户空间和内核空间

一个计算机通常有一定大小的内存空间,如一台计算机有4GB的地址空间,但是程序并不能完全使用这些地址空间,因为这些地址空间是被划分为用户空间和内核空间的。程序只能使用用户空间的内存,这里所说的使用是指程序能够申请的内存空间,并不是真正访问的地址空间。下面看下什么是用户空间和内核空间:

1、用户空间

用户空间是常规进程所在的区域,什么是常规进程,打开任务管理器看到的就是常规进程:

JVM就是常规进程,驻守于用户空间,用户空间是非特权区域,比如在该区域执行的代码不能直接访问硬件设备。

2、内核空间

内核空间主要是指操作系统运行时所使用的用于程序调度、虚拟内存的使用或者连接硬件资源等的程序逻辑。内核代码有特别的权利,比如它能与设备控制器通讯,控制着整个用于区域进程的运行状态。和I/O相关的一点是:所有I/O都直接或间接通过内核空间

那么,为什么要划分用户空间和内核空间呢?这也是为了保证操作系统的稳定性和安全性。用户程序不可以直接访问硬件资源,如果用户程序需要访问硬件资源,必须调用操作系统提供的接口,这个调用接口的过程也就是系统调用。每一次系统调用都会存在两个内存空间之间的相互切换,通常的网络传输也是一次系统调用,通过网络传输的数据先是从内核空间接收到远程主机的数据,然后再从内核空间复制到用户空间,供用户程序使用。这种从内核空间到用户控件的数据复制很费时,虽然保住了程序运行的安全性和稳定性,但是牺牲了一部分的效率。

最后,如何分配用户空间和内核空间的比例也是一个问题,是更多地分配给用户空间供用户程序使用,还是首先保住内核有足够的空间来运行,还是要平衡一下。在当前的Windows 32位操作系统中,默认用户空间:内核空间的比例是1:1,而在32位Linux系统中的默认比例是3:1(3GB用户空间、1GB内核空间)。

进程执行I/O操作的步骤

缓冲区,以及缓冲区如何工作,是所有I/O的基础。所谓"输入/输出"讲的无非也就是把数据移入或移出缓冲区。

进程执行I/O操作,归结起来,就是向操作系统发出请求,让它要么把缓冲区里的数据排干净(写),要么用数据把缓冲区填满(读)。进程利用这一机制处理所有数据进出操作,操作系统内部处理这一任务的机制,其复杂程度可能超乎想像,但就概念而言,却非常直白易懂,从上面的图,可以总结一下进程执行I/O操作的几步:

1、进程使用底层函数read(),建立和执行适当的系统调用,要求其缓冲区被填满,此时控制权移交给内核

2、内核随即向磁盘控制硬件发出命令,要求其从磁盘读取数据

3、磁盘控制器和数据直接写入内核内存缓冲区,这一步通过DMA完成,无需主CPU协助。这里多提一句,关于DMA,可以百度一下,它是现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU的大量中断负载,大大提升了整个系统的效率

4、一盘磁盘控制器把缓冲区填满,内核随即把数据从内核空间的临时缓冲区拷贝到进程执行read()调用时指定的缓冲区

5、进程从用户空间的缓冲区中拿到数据

当然,如果内核空间里已经有数据了,那么该数据只需要简单地拷贝出来即可。至于为什么不能直接让磁盘控制器把数据送到用户空间的缓冲区呢?最简单的一个理由就是,硬件通常不能直接访问用户空间。

同步和异步、阻塞和非阻塞

有了上面对于I/O的解读,我们来看一下同步和异步、阻塞和非阻塞两组概念的区别,主要二者在关注点上有所不同。

1、同步和异步

同步和异步这个概念比较广,不仅仅是在I/O,其他的还有诸如同步调用/异步调用、同步请求/异步请求,都是一个意思。同步和异步,关注的是消息通信机制

所谓同步,就是在发出一个"调用请求"时,在没有得到结果之前,该"调用请求"就不返回,但是一旦调用返回就得到返回值了。换句话说,就是由"调用者"主动等待"调用"的结果。像我们平时写的,方法A调用Math.random()方法、方法B调用String.substring()方法都是同步调用,因为调用者主动在等待这些方法的返回。

所谓异步,则正好相反,"调用"发出之后,这个调用就直接返回了,所有没有返回结果。换句话说,当一个异步调用请求发出之后,调用者不会立刻得到结果,因此异步调用适用于那些对数据一致性要求不是很高的场景,比如模块A更新了缓存中的某个值,模块B将某个内容分享到新浪微博,这些模块的关注点更多是"做了这件事"而不是"做了这件事是否马上成功",用分布式的话说,就是牺牲了系统的强一致性而提高了整个系统的可用性及分区容错性。如果这种场景下,我们希望获取异步调用的结果,"被调用者"可以通过状态、通知来通知调用者,或通过回调函数处理这个调用,对应Java中的有Future/FutureTask、wait/notify。

2、阻塞和非阻塞

阻塞和非阻塞关注的是程序在等待调用结果时的状态

阻塞调用指的是调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果之后才会返回。

非阻塞调用指的是在不能立即得到结果之前,该调用不会阻塞当前线程。

Linux网络I/O模型

由于绝大多数的Java应用都部署在Linux系统上,因此这里谈一下Linux网络I/O模型。

Linux的内核将所有外部设备都看做一个文件来操作,对一个文件的读写操作会调用内核提供的系统命令,返回一个file descriptor(fd,文件描述符)。而对一个Socket的读写也会有相应的描述符,称为Socketfd(Socket描述符),描述符就是一个数字,它指向内核中的一个结构体(结构体,C/C++数据类型,类似Java中的类,存储各种不同类型的数据,这里存储的是文件路径、数据区等一些属性)。

根据UNIX网络编程对I/O模型的分类,UNIX提供了5种I/O模型,分别为:

1、阻塞I/O模型

阻塞I/O模型就是最常用的I/O模型,缺省情况下所有的文件操作都是阻塞的,以Socket来讲解此模型:在用户空间中调用recvfrom,其系统调用直到数据包到达且被复制到应用进程的缓冲区或者发生错误时才返回,在此期间会一直等待,进程在从调用recvfrom开始到它返回的整段时间内都是被阻塞的,因此被称为阻塞I/O。

2、非阻塞I/O模型

recvfrom从用户空间到内核空间的时候,如果该缓冲区没有数据的话,就直接返回一个EWOULDBOCK错误,一般都对非阻塞I/O模型进行轮询检查这个状态,看内核空间是不是有数据到来,有数据到来则从内核空间复制数据到用户空间。

3、I/O复用模型

Linux提供select/poll,进程通过将一个或者多个fd传递给select或poll系统调用,阻塞在select操作上,这样select/poll可以帮助我们侦测多个fd是否处于就绪状态。select/poll是顺序扫描fd是否就绪,而且支持的fd数量有限,因此它的使用受到了一些制约。Linux还提供了一个epoll系统调用,epoll使用基于事件驱动方式替代顺序扫描,因此性能更高。当有fd就绪时,立即会掉函数rollback。

4、信号驱动I/O模型

首先开启Socket信号驱动I/O功能,并通过系统调用sigaction执行一个信号处理函数(此系统调用立即返回,进程继续工作,它是非阻塞的)。当数据准备就绪时,就为进程生成一个SIGIO信号,通过信号会掉通知应用程序调用recvfrom来读取数据,并通知主循环函数来处理数据。

5、异步I/O

告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核复制到用户自己的缓冲区)通知开发者。这种模型与信号驱动I/O模型的主要区别是:信号驱动I/O模型由内核通知开发者何时可以开始一个I/O操作,异步I/O模型由内核通知开发者I/O操作何时已经完成

原文:http://www.cnblogs.com/xrq730/p/5074199.html

java nio io模型的更多相关文章

  1. Java 网络 IO 模型

    在进入主题之前先看个 Java 网络编程的一个简单例子:代码很简单,客户端和服务端进行通信,对于客户端的每次输入,服务端回复 get.注意,服务端可以同时允许多个客户端连接. 服务端端代码: // 创 ...

  2. 阿里、腾讯热门面试题:聊聊Unix与Java的IO模型?(含详细解析)

    众所周知 如果去百度.腾讯等一线大厂面试,一定会深入考候选人的基础技术功底,其中尤为关键和重视的就是IO相关的技术和知识. 而要搞明白IO相关的概念,首先就得弄清楚同步与异步,阻塞与非阻塞到底是什么意 ...

  3. 通过实例理解Java网络IO模型

    网络IO模型及分类 网络IO模型是一个经常被提到的问题,不同的书或者博客说法可能都不一样,所以没必要死抠字眼,关键在于理解. Socket连接 不管是什么模型,所使用的socket连接都是一样的. 以 ...

  4. Java之IO模型

    首先来看一下同步与异步的概念: 1.同步是指当前端发起一次操作请求时,只有后台执行完所有的代码操作才会给前端返回值. 2.异步是将前端发回的消息加入消息队列,并且立刻给前端返回请求,告诉用户可以离开当 ...

  5. IO模型之AIO代码及其实践详解

    一.AIO简介 AIO是java中IO模型的一种,作为NIO的改进和增强随JDK1.7版本更新被集成在JDK的nio包中,因此AIO也被称作是NIO2.0.区别于传统的BIO(Blocking IO, ...

  6. Netty学习(1):IO模型之BIO

    概述 Netty其实就是一个异步的.基于事件驱动的框架,其作用是用来开发高性能.高可靠的IO程序. 因此下面就让我们从Java的IO模型来逐步深入学习Netty. IO模型 IO模型简单来说,就是采用 ...

  7. 从春节送祝福谈谈 IO 模型(二)

    上期结合程序员小猿用温奶器给孩子热奶的故事,把面试中常聊的“同步.异步与阻塞.非阻塞有啥区别”简单进行普及. 不过,恰逢春节即将到来,应个景,不妨就通过实现新春送祝福的需求,深入了解一下 Java I ...

  8. 从养孩子谈谈 IO 模型(一)

    同步/异步.阻塞/非阻塞 说的是一回事儿吗? 同步/异步.阻塞/非阻塞 你能通俗易懂的讲清楚吗? Java 中的 BIO.NIO.AIO 你了解吗? Socket 编程你还会吗? Linux 操作系统 ...

  9. Java NIO 转载

    原文:http://www.iteye.com/magazines/132-Java-NIO  Java NIO 系列教程 2014-04-28  编辑 wangguo 评论(71条) 有204256 ...

随机推荐

  1. SALT 加密

    大家都知道,MD5加密是不可逆.但事实上,我们通常值的MD5算法.黑客的眼下破解率相对较高.也有非常多站点上干脆就提供批量解密MD5的服务,当然是收费的.http://www.xmd5.org.这里提 ...

  2. Tomcat集群+Nginx+Redis服务搭建

    由于公司新业务突然上来了,单个Tomcat实例已经不能满足业务发展的需要了,只能通过搭建集群来解决问题了.所以就出现了下面的内容: 1.Redis保存Session信息 为了保存Session信息在集 ...

  3. iOS文档序列化(对象归档)

    对象归档: 概念: 对象归档是指将对象写入文件保存在硬盘,当再次又一次打开程序时,能够还原这些对象.也称:对象序列化.对象持久化. 数据持久性的方式(事实上就是3类) 1,NSKeyedArchive ...

  4. MySQL之自定义函数

    引言 MySQL本身提供了内置函数,这些函数的存在给我们日常的开发和数据操作带来了很大的便利,比如我前面提到过的聚合函数SUM().AVG()以及日期时间函数等等,可是我们总会出现其他的需求:我们需要 ...

  5. leetcode第29题--Substring with Concatenation of All Words

    problem: You are given a string, S, and a list of words, L, that are all of the same length. Find al ...

  6. nginx配置文件中的location详解

    location 语法:location [=|~|~*|^~] /uri/ { … } 默认:否 上下文:server 这个指令随URL不同而接受不同的结构.你可以配置使用常规字符串和正则表达式.如 ...

  7. JAVA开发语言基础

    很多时候我们都不知道,为什么android最开始要用java作为基础语言 看看知乎上都是怎么回答的 为什么java最初成为android开发的基础语言 ------------------------ ...

  8. Role Object(角色对象)

    Role Object(角色对象) 索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Role Object 的示例实现. 意图 通过明确地附加角色对象到目标对象中,以使对象可以 ...

  9. [置顶] 在js中如何实现方法重载?以及函数的参数问题

    都知道在js中没有办法直接实现方法重载,因为在js中如果定义了多个名称相同,但参数个数不一样的方法,其实只有最后一个方法能被真正调用,其他的方法都被覆盖掉了. 但每一个函数都有一个特殊的参数argum ...

  10. SZU:J38 Number Base Conversion

    Judge Info Memory Limit: 32768KB Case Time Limit: 1000MS Time Limit: 1000MS Judger: Number Only Judg ...