复习-JavaGuide-Io

io模型

转载自https://github.com/Snailclimb/JavaGuide (添加小部分笔记)感谢作者!

https://zhuanlan.zhihu.com/p/360878783 IO多路复用讲解,这是一个与系统底层有关的知识点,需要一些操作系统调用代码才知道IO多路复用省的时间。

I/O #

何为I/O #

  • I/O(Input/Output),即输入/输出 从计算机结构的角度来解读一下I/O,根据冯诺依曼结构,计算机结构分为5大部分:运算器控制器存储器输入设备输出设备 ly-20241212141951603 其中,输入设备:键盘;输出设备:显示器 网卡、硬盘既属于输入设备也属于输出设备
  • 输入设备向计算机输入(内存)数据,输出设备接收计算机(内存)输出的数据,即I/O描述了计算机系统外部设备之间通信的过程
  • 从应用程序的角度解读I/O
    • 为了保证系统稳定性和安全性,一个进程的地址空间划分为用户空间User space内核空间Kernel space kernel 英[ˈkɜːnl]
    • 平常运行的应用程序都运行在用户空间,只有内核空间才能进行系统态级别资源有关操作—文件管理、进程通信、内存管理
    • 如果要进行IO操作,就得依赖内核空间的能力,用户空间的程序不能直接访问内核空间
    • 用户进程要想执行IO操作,必须通过系统调用来间接访问内核空间
  • 对于磁盘IO(读写文件)网络IO(网络请求和响应),从应用程序视角来看,应用程序对操作系统的内核发起IO调用(系统调用),操作系统负责的内核执行具体IO操作
    • 应用程序只是发起了IO操作调用,而具体的IO执行则由操作系统内核完成
  • 应用程序发起I/O后,经历两个步骤
    • 内核等待I/O设备准备好数据
    • 内核将数据从内核空间拷贝到用户空间

有哪些常见的IO模型 #

UNIX系统下,包括5种:同步阻塞I/O同步非阻塞I/OI/O多路复用信号驱动I/O异步I/O

Java中3中常见I/O模型 #

BIO (Blocking I/O ) #

  • 应用程序发起read调用后,会一直阻塞,直到内核把数据拷贝到用户空间 ly-20241212141951883

NIO (Non-blocking/New I/O) #

  • 对于java.nio包,提供了ChannelSelectorBuffer等抽象概念,对于高负载高并发,应使用NIO
  • NIO是I/O多路复用模型,属于同步非阻塞IO模型
    • 一般的同步非阻塞 IO 模型中,应用程序会一直发起 read 调用。
      等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的**,**直到在内核把数据拷贝到用户空间。

      相比于同步阻塞 IO 模型,同步非阻塞 IO 模型确实有了很大改进。通过轮询操作,避免了一直阻塞。

      但是,这种 IO 模型同样存在问题:应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的。

      ★★ 也就是说,【准备数据,数据就绪】是不阻塞的。而【拷贝数据】是阻塞图源:《深入拆解Tomcat & Jetty》

      ...

io设计模式

转载自https://github.com/Snailclimb/JavaGuide (添加小部分笔记)感谢作者!

装饰器模式 #

​ 类图:
ly-20241212141951023

  • 装饰器,Decorator,装饰器模式可以在不改变原有对象的情况下拓展其功能

  • ★装饰器模式,通过组合替代继承来扩展原始类功能,在一些继承关系较复杂的场景(IO这一场景各种类的继承关系就比较复杂)下更加实用

  • 对于字节流,FilterInputStream(对应输入流)和FilterOutputStream(对应输出流)装饰器模式的核心,分别用于增强(继承了)InputStreamOutputStream子类对象的功能 Filter (过滤的意思),中间(Closeable)下面这两条虚线代表实现;最下面的实线代表继承 ly-20241212141951298

  • 其中BufferedInputStream(字节缓冲输入流)、DataInputStream等等都是FilterInputStream的子类,对应的BufferedOutputStream和DataOutputStream都是FilterOutputStream的子类

  • 例子,使用BufferedInputStream(字节缓冲输入流)来增强FileInputStream功能

    • BufferedInputStream源码(构造函数)

      private static int DEFAULT_BUFFER_SIZE = 8192;
      public BufferedInputStream(InputStream in) {
          this(in, DEFAULT_BUFFER_SIZE);
      }
      
      public BufferedInputStream(InputStream in, int size) {
          super(in);
          if (size <= 0) {
              throw new IllegalArgumentException("Buffer size <= 0");
          }
          buf = new byte[size];
      }
      
    • 使用

      try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("input.txt"))) {
          int content;
          long skip = bis.skip(2);
          while ((content = bis.read()) != -1) {
              System.out.print((char) content);
          }
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  • ZipInputStream和ZipOutputStream还可以用来增强BufferedInputStream和BufferedOutputStream的能力

    ...

io基础

转载自https://github.com/Snailclimb/JavaGuide (添加小部分笔记)感谢作者!

简介 #

  • IO,即Input/Output,输入和输出,输入就是数据输入到计算机内存;输出则是输出到外部存储(如数据库文件远程主机

  • 根据数据处理方式,又分为字节流字符流

  • 基类

    • 字节输入流 InputStream,字符输入流 Reader
    • 字节输出流 OutputStream, 字符输出流 Writer

字节流 #

  • 字节输入流 InputStream InputStream用于从源头(通常是文件)读取数据(字节信息)到内存中,java.io.InputStream抽象类是所有字节输入流的父类

    • 常用方法

      • read() :返回输入流中下一个字节的数据。返回的值介于 0 到 255 之间。如果未读取任何字节,则代码返回 -1 ,表示文件结束。
      • read(byte b[ ]) : 从输入流中读取一些字节存储到数组 b 中。如果数组 b 的长度为零,则不读取。如果没有可用字节读取,返回 -1。如果有可用字节读取,则最多读取的字节数最多等于 b.length , 返回读取的字节数。这个方法等价于 read(b, 0, b.length)
      • read(byte b[], int off, int len) :在read(byte b[ ]) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字节数)。
      • skip(long n) :忽略输入流中的 n 个字节 ,返回实际忽略的字节数。
      • available() :返回输入流中可以读取的字节数。
      • close() :关闭输入流释放相关的系统资源。
    • Java9 新增了多个实用方法

      ...