BIO:

  BIO是阻塞IO,体现在一个线程调用IO的时候,会挂起等待,然后Thread会进入blocked状态;这样线程资源就会被闲置,造成资源浪费,通常一个系统线程数是有限的,而且,Thread进入内核态也是很大的性能开销。而阻塞方式,意味着BIO必然是一个同步IO。

  BIO还有一个显著的特点是面向流式Stream编程,特点是实现简单,但也意味着拓展性差。

NIO:

  NIO,通常实现为同步非阻塞IO,同步意味着不会产生会调,需要线程自身去同步IO是否完成,而非阻塞就是线程会立刻返回。

  相对于BIO面向流式抽象思想编程,NIO是面向管道编程的,例如在Java中必谈的三个封装类Buffer、Channel、Sellector,就是管道编程的体现,Java1.4后提供的非阻塞 IO 的核心在于使用一个 Selector 来管理多个通道,可以是 SocketChannel,也可以是 ServerSocketChannel,将各个通道注册到 Selector 上,指定监听的事件。之后可以只用一个线程来轮询这个 Selector,看看上面是否有通道是准备好的,当通道准备好可读或可写,然后才去开始真正的读写,这样速度就很快了。我们就完全没有必要给每个通道都起一个线程。如下面代码所示:

 1 package com.mobisummer.spider.slave.task.aliexpress.region;
 2
 3 import java.io.IOException;
 4 import java.net.InetSocketAddress;
 5 import java.net.ServerSocket;
 6 import java.nio.ByteBuffer;
 7 import java.nio.channels.SelectionKey;
 8 import java.nio.channels.Selector;
 9 import java.nio.channels.ServerSocketChannel;
10 import java.nio.channels.SocketChannel;
11 import java.util.Iterator;
12 import java.util.Set;
13
14 public class PlainNioServer {
15
16   public void serve(int port) throws IOException {
17
18     ServerSocketChannel serverChannel = ServerSocketChannel.open();
19     serverChannel.configureBlocking(false);
20     ServerSocket ssocket = serverChannel.socket();
21     InetSocketAddress address = new InetSocketAddress(port);
22     ssocket.bind(address);
23     Selector selector = Selector.open();
24     serverChannel.register(selector, SelectionKey.OP_ACCEPT);
25     final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
26
27     for (; ; ) {
28       try {
29         selector.select();
30       } catch (IOException ex) {
31         ex.printStackTrace();
32         // handle exception
33         break;
34       }
35       Set<SelectionKey> readyKeys = selector.selectedKeys();
36       Iterator<SelectionKey> iterator = readyKeys.iterator();
37       while (iterator.hasNext()) {
38         SelectionKey key = iterator.next();
39         iterator.remove();
40         try {
41           if (key.isAcceptable()) {
42             ServerSocketChannel server = (ServerSocketChannel) key.channel();
43             SocketChannel client = server.accept();
44             client.configureBlocking(false);
45             client.register(selector,
46                             SelectionKey.OP_WRITE | SelectionKey.OP_READ,
47                             msg.duplicate());
48             System.out.println("Accepted connection from " + client);
49           }
50           if (key.isWritable()) {
51             SocketChannel client = (SocketChannel) key.channel();
52             ByteBuffer buffer = (ByteBuffer) key.attachment();
53             while (buffer.hasRemaining()) {
54               if (client.write(buffer) == 0) {
55                 break;
56               }
57             }
58             client.close();
59           }
60         } catch (IOException ex) {
61           key.cancel();
62           try {
63             key.channel().close();
64           } catch (IOException cex) {
65             // ignore on close
66           }
67         }
68       }
69     }
70   }
71 }

  对于并发数量大但处理的任务又十分快速的时候用处十分显著,代替了之前的利用多线程解决业务问题的方案,就是利用单线程以及底层epoll或者poll原理完成了单线程处理多任务的方案,理论上至少我们想到了减少线程切换的开支,而由内核去改变IO状态。

  【说说实现】

  NIO 中 Selector 是对底层操作系统实现的一个抽象,管理通道状态其实都是底层系统实现的,在不同系统下的实现会不同,是自动选择的,可能的实现方式如下:

  select:上世纪 80 年代的事情了,它支持注册 FD_SETSIZE(1024) 个 socket,在那个年代肯定是够用的。

  poll:1997 年,出现了 poll 作为 select 的替代者,最大的区别就是,poll 不再限制 socket 数量。

  select 和 poll 都有一个共同的问题,那就是它们都只会告诉你有几个通道准备好了,但是不会告诉你具体是哪几个通道。所以,一旦知道有通道准备好以后,自己还是需要进行一次扫描,显然这个不太好,通道少的时候还行,一旦通道的数量是几十万个以上的时候,扫描一次的时间都很可观了,时间复杂度 O(n)。所以,后来才催生了以下实现。

  epoll:2002 年随 Linux 内核 2.5.44 发布,epoll 能直接返回具体的准备好的通道,时间复杂度 O(1)。那么这个epoll是怎么的原理呢?这就涉及操作系统的中断了,在内核的最底层是中断,类似系统回调的机制。网卡设备对应一个中断号, 当网卡收到网络端的消息的时候会向CPU发起中断请求, 然后CPU处理该请求. 通过驱动程序 进而操作系统得到通知, 系统然后通知epoll, epoll改变阻塞状态。

  除了 Linux 中的 epoll,2000 年 FreeBSD 出现了 Kqueue,还有就是,Solaris 中有 /dev/poll。

  前面说了那么多实现,但是没有出现 Windows,Windows 平台的非阻塞 IO 使用 select,我们也不必觉得 Windows 很落后,在 Windows 中 IOCP 提供的异步 IO 是比较强大的。

AIO:

  异步这个词,我想对于绝大多数开发者来说都很熟悉,很多场景下我们都会使用异步。对于我而言比较有意义的事情就是发现我所在公司自己做的底层框架Lwmf,自己做了一个声称为AIO的实现,只不过是封装了一层罢。

  通常,我们会有一个线程池用于执行异步任务,提交任务的线程将任务提交到线程池就可以立马返回,不必等到任务真正完成。如果想要知道任务的执行结果,通常是通过传递一个回调函数的方式,任务结束后去调用这个函数。

  同样的原理,Java 中的异步 IO 也是一样的,都是由一个线程池来负责执行任务,然后使用回调或自己去查询结果,所以这里涉及了两个实现方式,在Java中就是注册回调函数和使用异步任务返回的Feature实例。

  干货在这里:对象是过程的抽象,而线程是调度的抽象;所以,设计异步IO的时候,需要把线程控制的牢牢的,才能更稳健的设计哦。

  最后,不得不提一下的就是Reactor模型和Netty框架了!但不是本文重点,但这确实是java中优秀的NIO实现

转载于:https://www.cnblogs.com/iCanhua/p/8547133.html

【谈谈IO】BIO、NIO和AIO相关推荐

  1. JAVA IO : BIO NIO AIO

    JAVA IO : BIO NIO AIO 同步异步.阻塞非阻塞概念 同步与异步 阻塞与非阻塞 IO VS NIO VS AIO 面向流与面向缓冲 阻塞与非阻塞IO BIO.NIO.AIO的JAVA实 ...

  2. Java之IO,BIO,NIO,AIO知多少?

    开心一笑 [一女人:"我真不放心丈夫,他准备到湖中心水最深的地方把猫扔掉."邻居:"那有什么不放心的?"女人:"猫已回家一钟头了!"] 提出 ...

  3. Java IO BIO NIO

    Java IO BIO NIO 一.Java I/O概述 1.1 什么是流 1.2 流的分类 1.3 字符流 1.3.1 Reader 1.3.2 Writer 1.4 字节流 1.4.1 Input ...

  4. Java之IO,BIO,NIO,AIO

    2019独角兽企业重金招聘Python工程师标准>>> 参考文献一 IO基础知识回顾 java的核心库java.io提供了全面的IO接口.包括:文件读写.标准设备输出等.Java中I ...

  5. IO: BIO ? NIO ? AIO?

    IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSock ...

  6. Java IO(BIO, NIO, AIO) 总结

    文章转载自:JavaGuide 目录 BIO,NIO,AIO 总结 同步与异步 阻塞和非阻塞 1. BIO (Blocking I/O) 1.1 传统 BIO 1.2 伪异步 IO 1.3 代码示例 ...

  7. java io bio nio aio 详解

    BIO.NIO.AIO的区别: BIO就是基于Thread per Request的传统server/client实现模式, NIO通常采用Reactor模式, AIO通常采用Proactor模式, ...

  8. nio和bio的原理_Java的BIO,NIO和AIO的区别于演进

    前言 Java里面的IO模型种类较多,主要包括BIO,NIO和AIO,每个IO模型都有不一样的地方,那么这些IO模型是如何演变呢,底层的原理又是怎样的呢? 本文我们就来聊聊. BIO BIO全称是Bl ...

  9. IO、NIO、AIO

    1.阻塞IO-Socket Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或应答网络请求. Socket和ServerSocket类库位于 ...

  10. BIO,NIO和AIO的区别

    BIO也就是同步阻塞的I/O,由JAVA程序自己处理I/O流操作;一个线程启用I/O请求后,必须等I/O处理完毕才能进行下一步; NIO是同步非阻塞的I/O,还是由JAVA处理应用操作,不过单独开启一 ...

最新文章

  1. 基于Linux的 Open×××网络之网络架构应用实例
  2. 中国恒大:半个月网上售房近10万套 认购金额1026.7亿元
  3. face3000 c++ 代码运行
  4. python接口自动化(三十)--html测试报告通过邮件发出去——中(详解)
  5. struts2框架单文件、多文件上传实例详解
  6. Python机器学习——如何shuffle一个数据集(ndarray类型)
  7. 百度地图KEY发布版SHA1和开发板SHA1如何获得
  8. [转载]年末致富有新招,写个程序抓红包
  9. 全球搜索引擎集合(主要有移动搜索APP的)
  10. 利用ffmpeg将H264解码为RGB
  11. fastreport 横向分栏_fastreport分栏分组显示问题(急贴盼解决)
  12. 单元格内容分列多行_『如何将excel单个表格里的多行数据分列』
  13. CMDB建设补充:教你用django+drf 怎么去生成漂亮的API文档
  14. 光学红外雨量IFR202型传感器应用于智慧灌溉智能家居地质灾害等行业
  15. 大数加法(测试数据不完全,可能会有出错个例)
  16. Linux查看cc编译器版本,如何查看linux版本(转)
  17. JVM性能调优(4)——性能调优工具
  18. 微信公众号自定义菜单失效,无法设置的解决方法
  19. Caffe2自定义Operator
  20. Android】源码编译 ---zzz

热门文章

  1. 数据库Mysql的学习(六)-子查询和多表操作
  2. guava API整理
  3. conflicting types for ‘方法名’ 的错误
  4. 关闭uboot MMU 会导致android2.3 S5pv210 系统不稳定?!why
  5. 在论坛中出现的各种疑难问题:日志收缩问题
  6. 验证码的设计,随机数的生成
  7. 注解的力量 -----Spring 2.5 JPA hibernate 使用方法的点滴整理(六): 一些常用的数据库 注解...
  8. MVC2中Area的路由注册实现
  9. css:学习CSS了解单位em和px的区别
  10. CSS样式表的规划与组织