java IO编程模型

转载地址:https://www.toutiao.com/a6487925921268367885/


很多开发者一直都以当架构师作为目标,虽然将来不一定能成为架构师,但是成为架构师你肯定得了解IO模型。如果你是一名JAVA初学者,你可能对IO模型用在什么地方感到困惑。IO模型与你写程序之间到底有什么关系呢?不管你是初学者,亦或是一名老鸟,对IO模型你是否又有所耳闻呢?当你与其他人交流分布式服务框架的底层时,你是否会感觉到困惑?其实分布式服务底层的实现也离不开IO模型的合理利用。下面我们讲通过图文来解释相关的IO模型。

在讲解IO模型前,先理解两个概念,用户空间和内核空间。

用户空间指的是常规进程所在的区域,打开机器中的任务管理器,你会看到一些常用的常规进程,需要特别指出的是Java虚拟机是常规进程,驻守于用户空间。

内核空间主要是操作系统运行时所使用的用于程序调度,连接硬件资源或者虚拟内存的程序逻辑。所有的IO都直接或者间接依赖内核空间。只有内核空间才能直接访问硬件设备,用户空间是无法直接访问硬件设备的。

用户程序不允许直接访问硬件资源,如果用户程序需要访问硬件资源,必需通过调用操作系统提供的接口方可以访问对应的硬件资源,这一过程我们称为系统调用(System call)。

下图是一个普通的磁盘IO的流程图:

想做Java架构师,但是你竟不知道IO模型和Java网络编程模型?

普通的磁盘IO示例

流程说明:

1.进程使用底层函数read()方法,执行系统调用,要求将其缓冲区填满,然后将系统控制权返还给内核空间。

2.内核空间向磁盘发出请求,要求读取数据。

3.磁盘控制器通过DMA(Direct Memory Access--直接存储器访问)将数据写入内核缓冲区,无需CPU协助。为什么说无需CPU协助呢,CPU主要承担运算功能及调度。

4.磁盘控制器把内核缓冲区填满后,内核把数据从内核空间的临时缓冲区拷备到进程调用read()方法所指定的缓冲区。

5.用户进程从对应的缓冲区获取数据。

对于一个IO来讲,会涉及到两个系统对象:一是用户进程(process),另一个是系统内核(kernel)。当一次IO发生时,会经历两个阶段:一是等待数据准备(Waiting for the data to be ready)。其二是将数据从内核拷备到用户进程中(Copying the data from the kernel to the process)。

首先理解阻塞与非阻塞。

阻塞指的是当任务执行中发起的请求因其请求的某个条件不满足,它将一直等待直到条件满足。

非阻塞是指当任务执行中当发现其请求的某个条件不满足时,立刻得到系统反馈其条件不满足,非阻塞不会一直等待。

IO主要包括以下五种基本模型:

1)blocking I/O 阻塞IO

2)nonblocking IO 非阻塞IO

3)IO multiplexing 多路复用IO

4)signal driven IO 信号驱动IO

5)asynchronous IO 异步IO

一、阻塞IO

想做Java架构师,但是你竟不知道IO模型和Java网络编程模型?

blocking IO Model

参考上图,当应用程序得到recvfrom命令时,会发起一次系统调用到系统内核,当系统内核数据没能准备好时,应用进程在处于阻塞状态,等待数据准备好。当系统内核数据准备好以后,应用程序会等待内核空间将数据拷备到用户空间。当内核空间返回OK的信号后,应用程序才结束了阻塞的状态。所以阻塞IO在IO的两个阶段都处于阻塞状态。

我们接解到的网络编程时的底层方法listen()、recv()、send()都属于阻塞IO,这会给网络编程带来很大的问题,一旦线程被阻塞,线程无法执行任何运算或者响应网络请求,却白白的占用了系统控制权。当面对这种情况时,一种比较好的方式是采取多线程。这样在某一个线程阻塞时,并不会影响其他线程的运行。那是不是多线程就完美的解决了这种问题了呢,其实并不是,当系统中的线程达到一定规模以后,线程栈将无法再创建新的线程,而且在线程数据膨胀后,线程上下文切换也会占用大量的时间,比较差的情况是造成服务崩溃,系统假死。很多时候,会考虑使用线程池的方式来实现,这将减少线程的创建和销毁过程,将线程采用复用的方式。这也很好的降低了系统开销,但是实际业务中,池也有大小,当请求量远超池所能承受的业务范围时,池的效果并不能很好体现,所以使用池必须考虑其所面临的业务规模,并依此来调整池的大小。

二、非阻塞IO

想做Java架构师,但是你竟不知道IO模型和Java网络编程模型?

nonblocking IO

参考上图,在采用非阻塞IO的情况下,当用户程序发起系统调用时,如果内核空间没有准备好,内核空间不会阻塞用户进程,而是直接响应一个信号告知用户程序,当前内核空间并没准备好数据,当用户空间收到内核空间的响应数据没准备好时,用户空间将再次发送read请求,直到内核空间准备好。一旦用户空间准备好了,用户空间再次发起系统调用时,内核空间将会将数据从内核空间拷备到用户空间。将用户进程收到内核空间反馈的OK状态后,用户进程将获取系统调度权,继续执行。我们会发现在此过程中用户空间在内核空间数据没准备好的情况下,需要不停的发起询问,这将非常耗费CPU,因此此种模式在单线程模式下不被推荐,但是在多线程的情况下,此模式就显示出了其优势。如selector()多路复用模式。可以用一个单独的线程来检测多个线程的请求是否就绪,这就是第三种模式多路复用IO模型。

三、多路复用IO

想做Java架构师,但是你竟不知道IO模型和Java网络编程模型?

多路复用IO模型

多路复用IO,采用的是select/epoll的方式,可以使用单个线程来监控多个网络连接IO,当有数据到达时,它会通知到对应的用户进程。当用户进程调用select时,整个进程是处于阻塞态的,内核会检测select所负责的所有Socket,当其中任意一个Socket数据准备好了,select会返回一个readable的信号,此后用户进程再发起一次系统调用,将数据从内核空间拷备到用户空间。

在多路复用IO模型中,对于单独的socket,其实都是设置成为非阻塞IO,只不过这个block托管给了select,而并不被Socket IO 所阻塞。在线程数据很小时,这种IO模式可能并不比多线程和非多个非阻塞IO表现的更好。

四、信号驱动IO模型。

信号驱动IO不大常用。此处仅作了解。

五、异步IO

想做Java架构师,但是你竟不知道IO模型和Java网络编程模型?

异步IO模型图

用户进程发起aio_read的系统调用后,会立刻得到内核空间的响应,用户空间可以处理自己的事情,此后内核空间就可以等待数据完成,将数据准备完成后,内核空间将数据拷备到用户空间,然后给用户进程发送一个完成的信号,这次IO交互就完成了

在JAVA服务端编程中存在三种编程模型。

BIO:在这种模型中,主多线程accept请求并阻塞,当请求到达到,服务端创建新的线程来处理这个请求socket,完成对客户端的响应,这种模式下线程数可能会爆炸。

NIO:在这种模型中,主要采用的是多路复用方式来实现。所以我们说的JAVA NIO并不是异步IO,而是同步非阻塞IO。

AIO:也叫NIO2.0,是基于异步IO模型的实现。比NIO编程模型简化了不少。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java IO编程Java语言中的一个重要组成部分,用于处理输入输出流,包括文件读取、网络通信、数据库操作等。以下是Java IO编程的超详细介绍: 1. Java IO模型 Java IO模型由InputStream和OutputStream两个抽象类构成。InputStream和OutputStream提供了大量的方法用于处理字节流输入输出。 2. 字节流和字符流 Java IO中的流分为两种:字节流和字符流。字节流主要用于二进制数据的读取和写入,而字符流主要用于字符数据的读取和写入。字节流处理的是字节数据,字符流处理的是字符数据。 3. 文件输入输出流 Java提供了FileInputStream和FileOutputStream用于读取和写入文件中的数据。FileInputStream从文件中读取数据,FileOutputStream将数据写入文件中。 4. 缓冲流 缓冲流是Java IO中常用的一种流,可以通过缓存机制提升输入输出性能。BufferedInputStream和BufferedOutputStream可以增加字节输入输出时的缓冲区大小,从而提高读写性能,BufferedReader和BufferedWriter可以增加字符输入输出时的缓冲区大小,提高读写性能。 5. 对象输入输出流 ObjectInputStream和ObjectOutputStream可以用来读取和写入Java对象。这两个流用于对象的序列化和反序列化,将对象转化为字节序列,或将字节序列转化为对象。 6. 网络输入输出流 Java提供了Socket、ServerSocket、DatagramSocket等类用于网络通信。对于网络输入输出,可以使用DataInputStream和DataOutputStream进行读写,也可以使用BufferedReader和PrintWriter进行读写。 7. 转换流 转换流可以用来转换字节流和字符流之间的读写,比如InputStreamReader和OutputStreamWriter可以将字节流转换为字符流,FileReader和FileWriter也可以转换为字符流。 8. 数据库输入输出流 Java中提供了JDBC(Java Database Connectivity)用于数据库操作。JDBC中的输入输出流用于读取和写入数据库中的数据。 以上是Java IO编程的超详细介绍,希望能对您有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值