常见的IO模型:

1、同步阻塞IO(Blocking IO): 在Java中,默认创建的socket都是阻塞。同步IO,是一种用户空间与内核空间的IO发起方式。同步IO是指用户空间的线程是主动发起IO请求的一方,内核空间是被动接受方。异步IO则反过来,是指系统内核是主动发起IO请求的一方,用户空间的线程是被动接受。

  • 阻塞IO的特点及优缺点:
  1. 阻塞IO的特点是:在内核进行IO执行的两个阶段,用户线程都被阻塞。
  2. 阻塞IO的优点:应用的程序开发非常简单;在阻塞等待数据期间,用户线程挂起。在阻塞期间,用户线程基本不会占用CPU。
  3. 阻塞IO的缺点:一般情况下,会为每个连接配备一个独立的线程;在高并发的应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换开销会非常巨大。因此,基本上阻塞IO模型在高并发应用场景下是不可。

2、同步非阻塞IO(Non-blocking IO): 非阻塞IO要求socket被设置为NONBLOCK。使用非阻塞模式的IO读写,叫作同步非阻塞IO(None Blocking IO),简称为NIO,在NIO模型中,应用程序一旦开始IO系统调用,会出现以下两种情况:

(1)在内核缓冲区中没有数据的情况下,系统调用会立即返回,返回一个调用失败的信息。

(2)在内核缓冲区中有数据的情况下,是阻塞的,直到数据从内核缓冲复制到用户进程缓冲。复制完成后,系统调用返回成功,应用进程开始处理用户空间的缓存。

  • 同步非阻塞IO的特点及优缺点:
  1. 同步非阻塞IO的特点:应用程序的线程需要不断地进行IO系统调用,轮询数据是否已经准备好,如果没有准备好,就继续轮询,直到完成IO系统调用。
  2. 同步非阻塞IO的优点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。
  3. 同步非阻塞IO的缺点:不断地轮询内核,这将占用大量的CPU时间,效率低下。

3、IO多路复用(IO Multiplexing):IO多路复用能够避免同步非阻塞IO模型中轮询等待的问题。经典的Reactor反应器设计模式,有时也称为异步阻塞IO,Java中的Selector选择器和Linux中的epoll都是这种模型。在Linux系统中,对应的系统调用为select/epoll系统调用。通过该系统调用,一个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是内核缓冲区可读/可写),内核能够将就绪的状态返回给应用程序。随后,应用程序根据就绪的状态,进行相应的IO系统。在IO多路复用模型中通过select/epoll系统调用,单个应用程序的线程,可以不断地轮询成百上千的socket连接,当某个或者某些socket网络连接有IO就绪的状态,就返回对应的可以执行的读写操作。

  • IO多路复用的特点及优缺点:
  1. IO多路复用模型的特点:IO多路复用模型的IO涉及两种系统调用(System Call),一种是select/epoll(就绪查询),一种是IO操作。IO多路复用模型建立在操作系统的基础设施之上,即操作系统的内核必须能够提供多路分离的系统调用select/epoll。和NIO模型相似,多路复用IO也需要轮询。负责select/epoll状态查询调用的线程,需要不断地进行select/epoll轮询,查找出达到IO操作就绪的socket连接。对于注册在选择器上的每一个可以查询的socket连接,一般都设置成为同步非阻塞模型。
  2. IO多路复用模型的优点:与一个线程维护一个连接的阻塞IO模式相比,使用select/epoll的最大优势在于,一个选择器查询线程可以同时处理成千上万个连接(Connection)。系统不必创建大量的线程,也不必维护这些线程,从而大大减小了系统的开销。Java语言的NIO(New IO)技术,使用的就是IO多路复用模型。在Linux系统上,使用的是epoll系统调用。
  3. IO多路复用模型的缺点:本质上,select/epoll系统调用是阻塞式的,属于同步IO。都需要在读写事件就绪后,由系统调用本身负责进行读写,也就是说这个读写过程是阻塞的。

4、异步IO(Asynchronous IO,简称为AIO): 指的是用户空间与内核空间的调用方式反过来。用户空间的线程变成被动接受者,而内核空间成了主动调用者。

  • 基本流程:用户线程通过系统调用,向内核注册某个IO操作。内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序,用户执行后续的业务操作。
  • 异步IO模型的特点:在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。用户线程需要接收内核的IO操作完成的事件,或者用户线程需要注册一个IO操作完成的回调函数。正因为如此,异步IO有的时候也被称为信号驱动IO。

异步IO异步模型的缺点:应用程序仅需要进行事件的注册与接收,其余的工作都留给了操作系统,也就是说,需要底层内核提供。

5、Java NIO由以下三个核心组件组成:Channel(通道)、Buffer(缓冲区)、Selector(选择器)。

(1)Buffer类:

  • Buffer类是一个非线程安全。MappedByteBuffer是专门用于内存映射的一种ByteBuffer类型。
  • Buffer类在其内部,有一个byte[]数组内存块,作为内存缓冲区。为了记录读写的状态和位置,Buffer类提供了一些重要的属性。其中,有四个重要的成员属性:capacity(容量)、position(读写位置)、limit(读写的限制)、mark(标记)
    1. Buffer类的capacity属性,表示内部容量的大小;Buffer类的capacity属性一旦初始化,就不能再改变。
    2. capacity容量不是指内存块byte[]数组的字节的数量。capacity容量指的是写入的数据对象的数量。
    3. 在读模式下,limit的值含义为最多能从缓冲区中读取到多少数据。
    4. 调用mark()方法设置mark=position,在调用reset()可以让position恢复到mark标记的位置即position=mark。
  • 新建一个缓冲区时,缓冲区处于写入模式,这时是可以写数据的。数据写入后,如果要从缓冲区读取数据,这就要进行模式的切换,可以使用(即调用)flip翻转方法,将缓冲区变成读取模式。在这个flip翻转过程中,position会进行非常巨大的调整,具体的规则是:position由原来的写入位置,变成新的可读位置,也就是0,表示可以从头开始读。flip翻转的另外一半工作,就是要调整limit属性。
  • 在读取完成后,可以调用Buffer.clear()清空或者Buffer.compact()压缩方法,再一次将缓冲区切换成写入模式。

(2)NIO Channel通道类:

大部分应用场景,从通道读取数据都会调用通道的int read(ByteBufferbuf)方法,它从通道读取到数据写入到ByteBuffer缓冲区,并且返回读取到的数据量;写入数据到通道。都会调用通道的int write(ByteBufferbuf)方法,参数—ByteBuffer缓冲区,是数据的来源。write方法的作用,是从ByteBuffer缓冲区中读取数据,然后写入到通道自身,而返回值是写入成功的字节数。

  • File Channel文件通道:FileChannel为阻塞模式,不能设置为非阻塞模式。
  • 新建的ByteBuffer,默认是写入模式,可以作为inChannel.read(ByteBuffer)的参数。inChannel.read方法将从通道inChannel读到的数据写入到ByteBuffer。
  • 在NIO中,涉及网络连接的通道有两个,一个是SocketChannel负责连接传输,另一个是ServerSocketChannel负责连接的监听。ServerSocketChannel应用于服务器端,而SocketChannel同时处于服务器端和客户端。无论是ServerSocketChannel,还是SocketChannel,都支持阻塞和非阻塞两种。

(3)NIO Selector:

选择器的使命是完成IO的多路复用。一个通道代表一条连接通路,通过选择器可以同时监控多个通道的IO(输入输出)状况。选择器和通道的关系,是监控和被监控的关系。调用通道的Channel.register(Selector sel,int ops)方法,可以将通道实例注册到一个选择器中。register方法有两个参数:第一个参数,指定通道注册到的选择器实例;第二个参数,指定选择器要监控的IO事件类型。

  • 可供选择器监控的通道IO事件类型,包括以下四种:

(1)可读:SelectionKey.OP_READ

(2)可写:SelectionKey.OP_WRITE

(3)连接:SelectionKey.OP_CONNECT

(4)接收:SelectionKey.OP_ACCEPT

事件类型的定义在SelectionKey类中。如果选择器要监控通道的多种事件,可以用“按位或”运算符来实现。

  • 判断一个通道能否被选择器监控或选择,有一个前提:判断它是否继承了抽象类SelectableChannel(可选择通道)。如果继承了SelectableChannel,则可以被选择,否则不能。一条通道若能被选择,必须继承SelectableChannel。
  • 一旦在通道中发生了某些IO事件(就绪状态达成),并且是在选择器中注册过的IO事件,就会被选择器选中,并放入SelectionKey选择键的集合中。通过SelectionKey选择键,不仅仅可以获得通道的IO事件类型,如SelectionKey.OP_READ;还可以获得发生IO事件所在的通道;另外,也可以获得选出选择键的选择器实例。
  • 使用选择器,主要有以下三步:

(1)获取选择器实例;(2)将通道注册到选择器中;(3)轮询感兴趣的IO就绪事件(选择键集合)。

注册到选择器的通道,必须处于非阻塞模式下,否则将抛出IllegalBlockingModeException异常。一个通道,并不一定要支持所有的四种IO事件。例如服务器监听通道ServerSocketChannel,仅仅支持Accept(接收到新连接)IO事件;而SocketChannel传输通道,则不支持Accept(接收到新连接)IO事件。可以在注册之前,可以通过通道的validOps()方法,来获取该通道所有支持的IO事件。

  • SelectionKey集合不能添加元素,如果试图向SelectionKey选择键集合中添加元素,则将抛出java.lang. Unsupported-OperationException异常。

select()方法返回的整数值(int整数类型),表示发生了IO事件的通道数量。更准确地说,是从上一次select到这一次select之间,有多少通道发生了IO事件。

6、NIO和OIO的区别:

(1)OIO是面向流(Stream Oriented)的,NIO是面向缓冲区(Buffer Oriented);

(2)OIO的操作是阻塞的,而NIO的操作是非阻塞,NIO使用了通道和通道的多路复用;

(3)OIO没有选择器(Selector)概念,而NIO有选择器的概念。

7、在NIO中,同一个网络连接使用一个通道表示,所有的NIO的IO操作都是从通道开始的。一个通道类似于OIO中的两个流的结合体,既可以从通道读取,也可以向通道写入。通道的读取,就是将数据从通道读取到缓冲区中;通道的写入,就是将数据从缓冲区中写入到通道。

Java并发编程学习-日记1、常见的IO模型、NIO、OIO相关推荐

  1. java并行任务,Java 并发编程学习(五):批量并行执行任务的两种方式

    Java 并发编程学习(五):批量并行执行任务的两种方式 背景介绍 有时候我们需要执行一批相似的任务,并且要求这些任务能够并行执行.通常,我们的需求会分为两种情况: 并行执行一批任务,等待耗时最长的任 ...

  2. java并发编程学习一

    java并发编程学习一 什么是进程和线程? 进程是操作系统进行资源分配的最小单位 进程跟进程之间的资源是隔离的,同一个进程之中的线程可以共享进程的资源. 线程是进程的一个实体,是CPU 调度和分派的基 ...

  3. 简明高效的 Java 并发编程学习指南

    你好,我是宝令,<Java 并发编程实战>专栏作者,很高兴你能看到这篇内容. 对于一个Java程序员而言,能否熟练掌握并发编程是判断他优秀与否的重要标准之一.因为并发编程是Java语言中最 ...

  4. Java并发编程学习 + 原理分析(建议收藏)

    总结不易,如果对你有帮助,请点赞关注支持一下 微信搜索程序dunk,关注公众号,获取博客源码 Doug Lea是一个无私的人,他深知分享知识和分享苹果是不一样的,苹果会越分越少,而自己的知识并不会因为 ...

  5. 海子Java并发编程学习总结

    2019独角兽企业重金招聘Python工程师标准>>> Java并发编程:进程和线程之由来 Java并发编程:如何创建线程? Java并发编程:Thread类的使用 Java并发编程 ...

  6. Java并发编程学习记录

    Java并发编程汇总 并发问题的分解 多线程并发的特性 volatile 在并发编程中可能出现的问题: 管程 wait() 的正确姿势 notify() 何时可以使用 在使用多线程编程的时候,开启多少 ...

  7. 【并发入门】Java 并发编程学习笔记

    注:该笔记主要记录自 B站 up主 遇见狂神说的个人空间_哔哩哔哩_bilibili 1.什么是 JUC Java 工具类中的 并发编程包 学习:源码 + 官方文档 业务:普通的线程代码 Thread ...

  8. java并发编程学习juc工具类之Executors

    文章目录 Executors 重要方法 1.newCachedThreadPool 2.newFixedThreadPool 3.newScheduledThreadPool 示例代码 4.newSi ...

  9. java 并发编程学习之二 ---- lock

    在Java中有两种方法实现锁机制,一种是在前一篇博客中([java7并发编程实战]-–线程同步机制:synchronized)介绍的synchronized,而另一种是比synchronized更加强 ...

最新文章

  1. Java面试题之Oracle 支持哪三种事务隔离级别
  2. lapack安装_VASP环境安装-BoltzTraP-1.2.5安装
  3. 如何替换所有出现的字符串?
  4. php、linux、javascript 正则表达式
  5. POJ 3616 Milking Time
  6. hive sql 学习笔记
  7. Java设计模式-工厂模式(3)抽象工厂模式
  8. 很多优秀人感觉是:让他实际工作,他可能会考虑得很全面,而答题的时候,他就显得比较马虎,完成要求就算结束...
  9. CalendarExtender控件的中文显示问题
  10. grep 正则匹配
  11. php7设置最大连接数,sybase 15.7 修改 number of user connections 最大连接数
  12. 【Python学习】 - plt画图时,添加标题的中英文问题
  13. HashMap、TreeMap、Hashtable、HashSet和ConcurrentHashMap区别
  14. 毕业设计--MySqL的初探
  15. UML概要基础知识(待完善)
  16. 怎么通过创新再造58
  17. 安装程序总是提示重启计算机,技巧|安装西门子软件反复提示重启电脑的解决方法...
  18. Deepin-WPS输出PDF文件过大的终极解决办法
  19. 添加遮罩css,添加遮罩层
  20. Apache APISIX 社区成员助力 openEuler 发布第一个社区创新版

热门文章

  1. Python 3 《Class》入门练习
  2. D-009 eMMC电路设计
  3. 小马哥----高仿苹果5se 机型界面图面面观,低配机型 谨防假冒
  4. 微信支付当前页面的URL未注册问题[单页面]
  5. 《Cisco VPP SFC》2、NSH_SFC 安装
  6. 在kitti数据集与nsh_indoor_outdoor.bag,自己数据集(RS_16)上运行LeGo-LOAM
  7. vim 去掉黄色阴影
  8. STM32项目分享---MQTT智能门禁系统(含APP控制)
  9. 耶斯莫拉~一起来学集合啊~
  10. 使用云服务器被攻击了怎么办