字符流、字节流、输入流、输出流

Java 中使用IO(输入输出)来读取和写入,读写磁盘文件、内存、网络数据。输入输出是相对内存而言,往内存中读数据就为输入流,从内存中往外写就是输出流。
根据处理类型分为字符流、字节流。

  • 字节流处理所有类型数据,以Stream结尾;

  • 字符流处理文本数据,以Reader、Writer结尾;
    Java IO类见下图:

    同步、异步、阻塞、非阻塞
    synchronous、asynchronous、blocking、non-blocking

    同步、异步关注的是消息通信机制
    同步,是在发起调用后,在得到结果前,该调用不会返回。等到调用返回后,就能拿到返回值。调用者主动等待调用结果。
    异步, 是在发起调用后,调用直接返回,所以无返回结果。后续通过状态、回调通知调用者。

    阻塞、非阻塞关注的是程序在等待调用结果(返回值、消息)时的状态
    阻塞调用,是指在调用结果返回前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
    非阻塞调用,是指在调用结果返回前,该调用不会阻塞当前线程。

    换句话说:
    同步、异步区别:是否需要等待调用结果,才能进行下一步。
    阻塞、非阻塞:进程\线程要访问的数据就绪前,进程\线程是否需要等待。

Linux的5种IO模型

  1. 阻塞IO模型
  2. 非阻塞IO模型
  3. IO复用模型
  4. 信号驱动IO模型
  5. 异步IO模型

1.阻塞IO模型
Linux中,默认情况下socket是阻塞的,一个典型的读操作流程如下:

当用户进程调用了recvfrom这个系统调用,kernel就开始了I/O的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。
当kernel一直等到数据准备好了,它就会将数据从kernel系统缓冲区中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。所以,blocking IO的特点就是在I/O执行的两个阶段都是block。
Windows Socket API
socket()函数和WSASocket()函数创建套接字时,默认的套接字是阻塞的。线程会阻塞等待,直到Windows Sockets API执行完成。
bind()、listen()函数,不会阻塞线程
可能会阻塞套接字的Windows Socket API调用分为4类

  1. 输入操作:recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。以阻塞套接字为参数的该函数接受数据。如果此时套接字缓冲区中无数据,则调用线程一直睡眠到数据到来

  2. 输出操作:send()、sendto()、WSASend()和WSASendto()函数。调用该函数发送数据。如果套接字缓冲区无可用空间,则调用线程会一直睡眠到有可用空间。

  3. 接受连接:accept()和WSAAcept()函数。以阻塞套接字为参数的该函数等待接受对方的连接请求。无则线程休眠。

  4. 外出连接:connect()和WSAConnect()函数。对于TCP连接,客户端以阻塞套接字为参数,调用该函数向服务器发起连接。
    该函数在接收到服务器的应答前,不会返回。 这意味着TCP连接总会等待至少到服务器的一次往返时间。

    阻塞模式的套接字,开发实现简单。但是并发能力较弱,扩展性弱。

2.非阻塞IO模型
Linux下,可以设置socket为non-blocking。这种情况下的读取流程如下:

用户进程调用recvfrom()时,如果kernal数据还未准备好,则直接返回error。用户线程不断重试,直到kernal准备好后,就马上将数据拷贝到用户内存,然后返回。所以这种模式下,用户线程需要不断主动询问kernal数据好了没。

3.IO复用模型(IO multiplexing)
IO复用模型又称event driven I/O,是在实际中使用最多的I/O模型。基本原理是select/epoll这个方法不断轮训所负责的socket,当某个socket有数据到达时,就通知用户线程。流程如下:

当用户线程调用select(),整个线程就会block,同时kernal会监听所有select负责的socket,一旦有socket的数据准备好了,select()就会返回。这时候用户线程再去调用read()操作,将数据从kernal拷贝到用户线程。
当线程数量较少时,这种方式可能比阻塞I/O模型效率更低,因为多了select()操作。select/epoll的优势是能处理更多的连接,在高并发场景效率更高。

4.信号驱动I/O模型(Signal-driven I/O)
首先我们需要允许套接字使用信号驱动IO,并安装一个信号处理函数,然后进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,在信号处理函数中调用IO操作函数处理数据。流程如下:(这种模型在实际中并不常用)

5.异步I/O模型(Asynchronous I/O)
这种模型不常用,流程如下:

用户线程发起read操作后,立刻就可以去做别的事情。从kernal角度,当它收到一个asynchroous read请求之后,会立刻返回,不会阻塞用户进程。然后kernal等待数据准备完成,将数据拷贝到用户内存,之后给用户进程发送一个signal,告诉它read操作完成了。

总结
1:blocking和non-blocking的区别
blocking IO会阻塞住对应的进程直到操作完成,non-blocking IO在kernal还未准备好数据的时候,直接返回。

1:synchronous I/O 和asynchronous IO的区别
区别在于synchronous I/O做I/O操作的时候会将进程阻塞。所以,blocking I/Onon-blocking I/OI/O multiplexingSignal-driven I/O都属于synchronous I/O,只有Asynchronous I/O属于asynchronous IO

扩展:select、poll、epoll简介
epoll跟select都能提供多路I/O复用的解决方案。在现在的Linux内核里有都能够支持,其中epoll是Linux所特有,而select则应该是POSIX所规定,一般操作系统均有实现。
1.select
select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是:

  1. 单个进程可监视的fd数量被限制,即能监听端口的大小有限:
    一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048

  2. 对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:
    当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。

  3. 需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大

    2.poll
    poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。
    它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有一个缺点:

    1. 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义
    2. poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd
    

    3.epoll
    epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。
    epoll的优点:

  4. 没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口)

  5. 效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数
    即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll

  6. 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销

select、poll、epoll 区别

select 内核需要将消息传递到用户空间,都需要内核拷贝动作
poll 同上
epoll epoll通过内核和用户空间共享一块内存来实现

4、Linux I/O模型总结

综上,在选择select,poll,epoll时要根据具体的使用场合以及这三种方式的自身特点:

1、表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。
2、select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善

基础篇--Java IO--概览相关推荐

  1. Java基础篇--Java 数组

    Java基础篇--Java 数组 Java 数组 声明数组变量 创建数组 处理数组 For-Each 循环 数组作为函数的参数 数组作为函数的返回值 多维数组 多维数组的动态初始化(以二维数组为例) ...

  2. JavaSE基础篇--Java SE语法02--基本语法

    JavaSE基础篇 Java SE语法02 HelloWorld 基本语法 流程控制 方法 数组 基本语法 标识符 关键字 数据类型 运算符 数据类型转换 运算后结果的数据类型 Java SE语法02 ...

  3. Java基础篇:IO流

    文章目录 一.File类的使用 File类的概述 File类的实例化 File类的常用方法 二.IO流原理及流的分类 Java IO原理 流的分类 流的体系结构 输入.输出的标准化过程 三.节点流(文 ...

  4. 图学java基础篇之IO

    java io体系 如图可以看出,java的io按照包来划分的话可以分为三大块:io.nio.aio,但是从使用角度来看,这三块其实揉杂在一起的,下边我们先来概述下这三块: io:主要包含字符流和字节 ...

  5. 【JAVA基础篇】IO流

    一.流的概念 "对语言设计人员来说,创建好的输入/输出系统是一项特别困难的任务." ――<Think in Java> 无论是系统.还是语言的设计中IO的设计都是异常复 ...

  6. Java IO篇 Java IO编程

    Java IO 一.java io 概述 1.1 相关概念 二.Java IO类库的框架 2.1 Java IO的类型 2.2 IO 类库 三.Java IO的基本用法 3.1 Java IO :字节 ...

  7. 【Java基础】Java IO编程:输入输出流、内存流、打印流、缓冲流BufferedReader、扫描流Scanner、序列化与反序列化

    文章目录 第11章.Java IO编程 11.1 文件操作类:File 11.2 字节流与字符流 字节输出流:OutputStream OutputStream类 FileOutputStream类 ...

  8. java基础-4 JAva IO

    JAva IO File类 File类介绍: 它是文件和目录路径名的抽象表示文件和目录是可以通过File封装成对象的对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已.它可以是存 ...

  9. 「ML 基础篇」机器学习概览

    文章目录 1. 什么是机器学习 2. 引入机器学习 3. 应用场景 4. 机器学习分类 4.1. 有无人类监督 4.2. 是否增量学习 4.3. 泛化方式 5. 主要挑战 6. 测试与验证 1. 什么 ...

最新文章

  1. 焊接工具DIY电焊机,自动触发笔,手持电焊笔
  2. php htmlentities函数的问题
  3. 【大会】看案例,选方案
  4. 前端学习(6):javascript简介
  5. 【网络流24题】餐巾计划问题(费用流)
  6. C++ 智能指针shared_ptr、weak_ptr的简单实现
  7. Linux之yum软件管理
  8. 如何制作多合一Windows镜像
  9. MATLAB鲁棒控制器实现
  10. 遇到的几个运放精密整流电路
  11. 计算机网络微课笔记03
  12. c语言间接寻址与指针,C语言中指针是不是用汇编的间接寻址实现的?
  13. 2021年职业院校技能大赛“网络安全”项目江西省A模块
  14. 华人最多的和比例最高的国家
  15. DLP是如何防止数据泄露的?
  16. 一文解析推特上最常见的加密骗局
  17. TCP/IP,TCPsocket,tcp协议的特点,tcp报文段最长字节数,tcp头内容,确认号和超时时限的设定细节,tcp协议是GBN和SR的混合体,
  18. CS61A Lab 1
  19. golang 撤回_Activiti6.0版本流程撤回、跳转、回退等操作
  20. gta5线上模式进不去云服务器,gta5ol线上连不上服务器|云端存档同步发生错误

热门文章

  1. 关联规则java代码_重量挖掘关联规则挖掘方法,哪个大神可以将以下伪代码转换为Java代码?...
  2. pythonrequests说明_解决Python requests 报错方法集锦
  3. 服务器线程数一直增加,.NET Core中遇到奇怪的线程死锁问题:内存与线程数不停地增长...
  4. c++ long 转 short_C精品编程之——C语言的数据类型、运算符、表达式,精品课程...
  5. 你永远都不知道你老公可以多幼稚......
  6. 假如你学过高数,那你这一辈子都不会忘记这个人
  7. 数学界的高冷之王,N次拒绝巨额奖金:我穷,但是我不缺钱。。。
  8. mysql sleep详解_sql注入详解(二)
  9. float型y取值在1.0c语言表达式,2011年全国计算机二级C语言模拟试题及答案(14)...
  10. c语言字符比较思路,C语言讲解思路资料