Java NIO1:I/O模型概述

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的理解,我们就可以理解一下同步和异步的区别了。

同步和异步的关注点是用户线程和内核的交互方式。同步指的是用户线程发起I/O请求后需要等待或者轮询内核I/O操作完成后才能继续执行;异步是指用户线程发起I/O请求后仍然继续执行,当内核I/O操作完成后会通知用户线程,或者调用用户线程注册的回调函数。

阻塞和非阻塞的关注点是用户线程调用内核操作的方式。阻塞是指I/O操作需要彻底完成后才返回到用户空间,非阻塞是指I/O操作被调用后立即返回给用户一个状态值,无需等到I/O操作彻底完成。

同步阻塞I/O

同步阻塞I/O模型,最简单的I/O模型,用户线程在内核进行I/O操作时被阻塞。

同步阻塞I/O的操作为,用户线程通过系统调用read()函数,发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达之后,然后将接收到的数据拷贝到用户空间,完成read()操作。整个过程中,用户线程需要等待read()函数将数据读取到用户空间缓冲区,才能够继续处理接收的数据。这将导致用户线程发起I/O请求时,不能做任何事情,对CPU的资源利用率不够

同步非阻塞I/O

同步非阻塞I/O模型是建立在同步阻塞I/O模型的基础上的,用户线程发起I/O请求之后可以立即返回。

同步非阻塞I/O的操作,上面已经说了,用户线程发起I/O请求之后立即返回,但此时并未读取到任何数据,用户线程需要不断发起I/O请求,直到数据到达之后,才真正地读到数据,继续执行。整个过程中,用户需要不断地调用read(),尝试是否可以读取成功,读取成功才继续处理接收的数据。这样,虽然用户线程每次发起I/O请求后可以立即返回,但是这并没有什么意义,为了等到数据,仍然需要不断轮询、重复请求,消耗了大量的CPU资源,因此一般很少使用这种模型。

I/O多路复用

I/O多路复用模型是建立在内核提供的多路分离函数select基础之上的,使用select函数可以避免同步非阻塞I/O模型中轮询等待的问题。

I/O多路复用的操作位,用户线程首先将需要进行的I/O操作添加到select中,然后阻塞等待select系统调用返回。当数据到达时,I/O操作被激活,select函数返回,用户线程正式发起read()请求,读取数据并继续执行。

从流程上来看,使用select函数进行I/O请求和同步阻塞模型没有太大区别甚至还多了添加监视I/O,以及调用select函数的额外操作,效率更差。但是,使用select函数以后的最大优势就是可以在一个线程内同时处理多个I/O请求。用户可以注册多个I/O,然后不断地调用select读取被激活的I/O,即可达到在同一个线程内同时处理多个I/O请求的目的。而在同步阻塞模型中,用户必须通过多线程的方式才能达到这个目的地。

然而,使用select函数的优点并不仅限于此。虽然上述方式允许单线程内处理多个I/O请求,但是每个I/O请求的过程还是阻塞的(在select函数上阻塞),平均时间甚至比同步阻塞I/O模型还要长。如果用户线程只注册自己感兴趣的I/O请求,然后去做自己的事情,等到数据到来时再进行处理,那么则可以提高CPU的利用率。

I/O多路复用模型是最常使用的I/O模型,但是其异步程度还不够彻底,因为它使用了会阻塞线程的select系统调用。因此I/O多路复用模型只能称为异步阻塞I/O,而非真正的异步I/O。

时间: 2024-10-12 07:32:20

Java NIO1:I/O模型概述的相关文章

MVC模型概述(1)

摘自( 私塾在线,跟开涛学SpringMVC) 1.标准MVC模型概述       MVC模型(Model-View-Controller)是一种架构型的模式,本身不引入新功能,只是帮助我们将开发的结构组织的更加合理,使展示与模型分离.流程控制逻辑.业务逻辑调用与展示逻辑分离. Model提供要展示的数据.View负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西.Controller接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示

Bean(描述Java的软件组件模型)

EJB是Enterprise Java Bean的缩写,一个Bean扮演着应用程序素材的角色.它包含有一个functional interface,一个life-cycle interface,以及一个实现它所支援的商业方法的类别. 外文名 Enterprise Java Bean 缩    写Bean   定义描述Java的软件组件模型 类    型    应用程序素材的角色 目    的  将可以重复使用的软件代码打包 应用范围  应用于服务器的部件 1定义 JavaBean是描述Java的

java虚拟机之内存模型

1. 概述 对于从事 C.C++ 程序开发的人员来说,在内存管理领域,他们既是拥有最高权力的「皇帝」又是从事基础工作的「劳动人民」 --- 既拥有每个对象的「所有权」,又担负着每一个对象生命开始到终结的维护责任. 但是对于 java 程序员来说,在虚拟机自动内存管理机制的帮助下,不需要再为每一个 new 操作写配对的 delete/free 代码,不容易出现在内存泄漏和内存溢出问题,由虚拟机管理内存这一切看起来都很美好.不过,也正是因为 java 程序员把内存控制的权利交给了 java 虚拟机,

Java的多线程编程模型5--从AtomicInteger开始

Java的多线程编程模型5--从AtomicInteger开始 2011-06-23 20:50 11393人阅读 评论(9) 收藏 举报 java多线程编程jniinteger测试 AtomicInteger,一个提供原子操作的Integer的类.在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字.而AtomicInteger则通过一种线程安全的加减操作接口. 来看AtomicInteger提供的接口. //获取当前的值 publ

权限系统与RBAC模型概述

为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/3793894.html 0. 前言 一年前,我负责的一个项目中需要权限管理.当时凭着自己的逻辑设计出了一套权限管理模型,基本原理与RBAC非常相似,只是过于简陋.当时google了一些权限管理的资料,从中了解到早就有了RBAC这个东西.可惜一直没狠下心来学习. 更详细的RBAC模型非常复杂.本文只做了一些基础的理论性概述.

推荐系统的几种常见模型概述

某个选修课的论文,这里贴过来,之所以贴过来,是因为我认为自己写的确实非常有意义,网上对这个东西确实没有很系统的中文介绍,我自己也是看了许多论文自己也动手做了很多很多实践才领悟的. 这个只是概论,以后有时间再加上具体的模型.算法. ----------------------------------------------------------------------------- 总的来说,推荐系统的目标可以分为预测评分和物品推荐两种,目前对前者的研究也更多,因为前者更适合建复杂的模型,所以这

CSS框模型(框模型概述、内边距、边框、外边距、外边距合并)

CSS 框模型概述 CSS 框模型 (Box Model) 规定了元素框处理元素内容.内边距.边框 和 外边距 的方式. 元素框的最内部分是实际的内容,直接包围内容的是内边距.内边距呈现了元素的背景.内边距的边缘是边框.边框以外是外边距,外边距默认是透明的,因此不会遮挡其后的任何元素. 内边距.边框和外边距都是可选的,默认值是零.但是,许多元素将由用户代理样式表设置外边距和内边距.可以通过将元素的 margin 和 padding 设置为零来覆盖这些浏览器样式.这可以分别进行,也可以使用通用选择

java多线程 生产消费者模型

[seriesposts sid=500] 下面的代码讲述了一个故事 一个面包生产铺里目前有30个面包,有三个人来买面包,第一个人要买50个,第二个要买20个,第三个要买30个. 第一个人不够,所以等着,让第二个买了.面包铺继续生产面包.有7个人在生产. package com.javaer.thread; public class CPMode { public static void main(String[] args) { Godown godown = new Godown(30);

Java虚拟机:内存模型详解

版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实例的时候,虚拟机要为对象分配内存,Java虚拟机又是如何配分内存的呢?这些都涉及到Java虚拟机的内存划分机制,今天我们就来探究一下Java虚拟机的内存模型. Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间,有的区域随

CSS 框模型概述

CSS 框模型 (Box Model) 规定了元素框处理元素内容.内边距.边框 和 外边距 的方式. CSS 框模型概述 元素框的最内部分是实际的内容,直接包围内容的是内边距.内边距呈现了元素的背景.内边距的边缘是边框.边框以外是外边距,外边距默认是透明的,因此不会遮挡其后的任何元素. 提示:背景应用于由内容和内边距.边框组成的区域. 内边距.边框和外边距都是可选的,默认值是零.但是,许多元素将由用户代理样式表设置外边距和内边距.可以通过将元素的 margin 和 padding 设置为零来覆盖