一文让你了解透彻Java中的IO模型
作者:小小小小明明明明明明明明
什么是IO
IO(Input/Output),也就是输入和输出的简称,从计算机结构的角度来看,IO,就是输入数据到计算机中,计算机输出数据到计算机外,下面有一张十分经典的冯·诺伊曼结构图,将计算机分为五大部分:运算器、控制器、存储器、输入设置、输出设备。
输入设备向计算机输入数据,输出设备接收计算机输出的数据。
所以,从计算机结构的角度来看IO,IO就是描述了计算机系统和外部设备之间通信的过程。
接下来我们再从应用程序的角度去了解一下IO:在操作系统中,为了保证操作系统的稳定性和安全性,一个进程的地址空间被划分为了用户空间(User space)和内核空间(Kernel space) 。
那么什么是用户空间,什么是内核空间呢?
- 用户空间是普通应用程序可访问的内存区域。
- 内核空间是操作系统内核访问的区域,独立于普通的应用程序,是受保护的内存空间。
可以简单的理解为我们平常运行的应用程序,都是运行在用户空间中的,它没有权限去进行一些系统态级别的资源相关操作,比如文件管理、内存管理、等等,这些操作都是要依赖内核空间才能完成,也就是说,我们如果想要进行IO操作,一定是要依赖内核空间的能力,并且这里需要注意一点:用户空间的程序不能直接访问内核空间。
那么如果要发起一次IO操作,那应该怎么办呢?
当我们需要执行一次IO操作的时候,由于没有执行IO操作的权限,只能发起系统调用请求操作系统来帮忙完成,所以用户进程想要执行IO操作的话,必须通过系统调用来间接的访问内核空间,比如我们最常见的IO操作就是磁盘IO(读写文件)和网络IO(网络请求和响应)。
那么从应用程序的视角去看IO的话,我们的应用程序发起对操作系统的内核发起IO调用(系统调用,注意只是调用),操作系统去负责内核执行具体的IO操作。(如果这段话不是很好理解,可以理解为调包,比如别人写好了的工具类,我们不需要关注里面的实现细节,只需要调用它的方法就好了,这里我们的应用程序就是发起了一个调用,但是真正执行的还是我们的操作系统)
当应用程序发起IO调用之后,会经历下面两个步骤:(这里一定要记住这两点,它和后面息息相关!)
- 内核等待IO设备准备好数据
- 内核将数据从内核空间拷贝到用户空间
常见的IO模型
IO模型有很多种(比如在UNIX系统下,IO模型一共分为5种:同步阻塞IO、同步非阻塞IO、IO多路复用、信号驱动IO、异步IO),本篇文章只讲述Java中的IO模型,Java中的IO被分为三类:BIO、NIO、AIO。
BIO(Blocking IO)
BIO属于同步阻塞IO模型,应用程序发起read调用之后,会一直阻塞,直到内核把数据从内核空间拷贝至用户空间。
BIO就是Java中最传统的IO模型,相关的类和接口都在java.io这个包下面,因为现在用的人很少(后面看它的特点就知道为什么了),所以我们这里简单介绍一下它的一些特点就好了。
- 对高并发场景下对于线程资源的消耗较高,每一个连接需要使用一条线程单独处理。
- 传输较小对象时存在频繁的线程上下文切换等性能问题。
如何优化
那么怎么去优化这个BIO呢?
首先上面说了BIO的缺点之一就是它是有多少连接就需要多少线程的模型,但是对于用户来说,打开一个连接,然后关闭一个连接是十分常见且频繁的事情,而与之对应的就是创建线程和销毁线程,但是创建线程和销毁线程对于操作系统来说是十分消耗资源的,所以想到的优化就是使用线程池去进行优化BIO。
NIO的面世
但是BIO的模型决定了它的上限,它始终是同步阻塞的IO模型,阻塞就会导致不能使用单线程处理多个请求,所以这个时候就需要修改它的模型,将调用read()、write()方法不再是阻塞的,这样就可以使用单线程处理多个请求,而这样就不再是同步阻塞的IO模型了,也就是我们下面要说到的NIO了。
NIO(Non-blocking/New IO)
Java的NIO是Java1.4引入的,对应的是java.nio包,提供了channel、selector、buffer等抽象。
Java中的NIO可以看作是IO多路复用模型,但是也有人认为它是同步非阻塞IO模型,这里我们先简单介绍一下这两种模型:
同步非阻塞IO模型
这个相比同步阻塞IO模型,同步非阻塞IO模型就是通过轮询的方式,避免了一直阻塞。
但是从图中也能看出问题所在,就是应用程序不断的进行IO系统调用轮询数据是否已经准备就绪的这段时间,是十分消耗CPU资源的(说白话就是反复调用read操作) 。
所以这个时候就引入了IO多路复用模型。
IO多路复用模型
在IO多路复用模型中,线程首先发起select调用,询问内核数据是否准备就绪,等待内核把数据准备好了,会返回一个ready调用,告诉你,我准备好了,这个时候用户线程再发起read调用。注意:read调用的过程依然是阻塞的(数据从内核空间拷贝至用户空间这段时间) 。
IO多路复用模型通过无效的系统调用,减少了对CPU资源的消耗。
Java中的NIO
Java中的NIO,有一个十分重要的概念,就是选择器(selector),也被称为多路复用器,通过它就可以实现使用一个线程管理多个客户端连接(这里是不是和BIO就不一样了,最大的优化的点就在这里) 。当客户端数据到了之后,线程再为客户端进行服务。
下面给出一张JavaNIO的图:
这张图就能很好的说明了NIO的特点了。
AIO(Asynchronous IO)
AIO,也被称为NIO 2.0,Java7中引入的异步IO模型,很多人都不理解非阻塞IO和异步IO到底有什么差别,其实异步IO就是基于事件和回调机制去实现的,也就是说用户调用操作之后会立马返回,不会阻塞,当后台处理完成,操作系统会通知相应的线程进行后续操作。
目前来说AIO的应用还没有十分广泛,应用最多的是NIO。
总结
最后放一张图来总结Java中的IO模型:
到此这篇关于一文让你了解透彻Java中的IO模型的文章就介绍到这了,更多相关Java IO模型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!