zoukankan      html  css  js  c++  java
  • BIO NIO AIO之间的区别

    一、BIO、NIO、AIO的基本定义与类比描述:
    BIO (Blocking I/O):同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子,这里假设一个烧开水的场景,有一排水壶在烧开水,BIO的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。
    NIO (New I/O):同时支持阻塞与非阻塞模式,但这里我们以其同步非阻塞I/O模式来说明,那么什么叫做同步非阻塞?如果还拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。
    AIO ( Asynchronous I/O):异步非阻塞I/O模型。异步非阻塞与同步非阻塞的区别在哪里?异步非阻塞无需一个线程去轮询所有IO操作的状态改变,在相应的状态改变后,系统会通知对应的线程来处理。对应到烧开水中就是,为每个水壶上面装了一个开关,水烧开之后,水壶会自动通知我水烧开了
     
     
    二、进程中的IO调用步骤大致可以分为以下四步:
    1.进程向操作系统请求数据 ;
    2.操作系统把外部数据加载到内核的缓冲区中;
    3.操作系统把内核的缓冲区拷贝到进程的缓冲区 ;
    4.进程获得数据完成自己的功能 ;
     
    当操作系统在把外部数据放到进程缓冲区的这段时间(即上述的第二,三步),如果应用进程是挂起等待的,那么就是同步IO,反之,就是异步IO,也就是AIO 。
     
    三、各自的特点
    1)BIO(Blocking I/O)同步阻塞I/O 
        会阻塞每一个线程
     
        在高并发的web或者tcp服务器中采用BIO模型就无法应对了,如果系统开辟成千上万的线程,那么CPU的执行时机都会浪费在线程的切换中,使得线程的执行效率大大降低。
     
    2)NIO (New I/O) 同步非阻塞I/O 
        只阻塞一个线程
     
    NIO是New I/O的简称,与旧式的基于流的I/O方法相对,从名字看,它表示新的一套Java I/O标 准。它是在Java 1.4中被纳入到JDK中的,并具有以下特性:
    – NIO是基于块(Block)的,它以块为基本单位处理数据
    – 为所有的原始类型提供(Buffer)缓存支持
    – 增加通道(Channel)对象,作为新的原始 I/O 抽象
    – 支持锁和内存映射文件的文件访问接口
     – 提供了基于Selector的异步网络I/O
     
    关于NIO弄清除 Channel、Buffer、Selector三个类之间的关系就可以了
     
    Channel
    首先说一下Channel,国内大多翻译成“通道”。Channel和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream。而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作,NIO中的Channel的主要实现有:FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel;通过看名字就可以猜出个所以然来:分别可以对应文件IO、UDP和TCP(Server和Client)。
     
    Buffer
    NIO中的关键Buffer实现有:ByteBuffer、CharBuffer、DoubleBuffer、 FloatBuffer、IntBuffer、 LongBuffer,、ShortBuffer,分别对应基本数据类型: byte、char、double、 float、int、 long、 short。
     
    Selector
    Selector 是NIO相对于BIO实现多路复用的基础,Selector 运行单线程处理多个 Channel,如果你的应用打开了多个通道,但每个连接的流量都很低,使用 Selector 就会很方便。例如在一个聊天服务器中。要使用 Selector , 得向 Selector 注册 Channel,然后调用它的 select() 方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新的连接进来、数据接收等。
     
     1 import java.io.IOException;
     2 import java.net.InetSocketAddress;
     3 import java.nio.channels.SelectionKey;
     4 import java.nio.channels.Selector;
     5 import java.nio.channels.ServerSocketChannel;
     6 import java.util.Iterator;
     7  
     8 public class TCPServerSelector{
     9     //缓冲区的长度
    10     private static final int BUFSIZE = 256;
    11     //select方法等待信道准备好的最长时间
    12     private static final int TIMEOUT = 3000;
    13     public static void main(String[] args) throws IOException {
    14         if (args.length < 1){
    15             throw new IllegalArgumentException("Parameter(s): <Port> ...");
    16         }
    17         //创建一个选择器
    18         Selector selector = Selector.open();
    19         for (String arg : args){
    20             //实例化一个信道
    21             ServerSocketChannel listnChannel = ServerSocketChannel.open();
    22             //将该信道绑定到指定端口
    23             listnChannel.socket().bind(new InetSocketAddress(Integer.parseInt(arg)));
    24             //配置信道为非阻塞模式
    25             listnChannel.configureBlocking(false);
    26             //将选择器注册到各个信道
    27             listnChannel.register(selector, SelectionKey.OP_ACCEPT);
    28         }
    29         //创建一个实现了协议接口的对象
    30         TCPProtocol protocol = new EchoSelectorProtocol(BUFSIZE);
    31         //不断轮询select方法,获取准备好的信道所关联的Key集
    32         while (true){
    33             //一直等待,直至有信道准备好了I/O操作
    34             if (selector.select(TIMEOUT) == 0){
    35                 //在等待信道准备的同时,也可以异步地执行其他任务,
    36                 //这里只是简单地打印"."
    37                 System.out.print(".");
    38                 continue;
    39             }
    40             //获取准备好的信道所关联的Key集合的iterator实例
    41             Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
    42             //循环取得集合中的每个键值
    43             while (keyIter.hasNext()){
    44                 SelectionKey key = keyIter.next();
    45                 //如果服务端信道感兴趣的I/O操作为accept
    46                 if (key.isAcceptable()){
    47                     protocol.handleAccept(key);
    48                 }
    49                 //如果客户端信道感兴趣的I/O操作为read
    50                 if (key.isReadable()){
    51                     protocol.handleRead(key);
    52                 }
    53                 //如果该键值有效,并且其对应的客户端信道感兴趣的I/O操作为write
    54                 if (key.isValid() && key.isWritable()) {
    55                     protocol.handleWrite(key);
    56                 }
    57                 //这里需要手动从键集中移除当前的key
    58                 keyIter.remove();
    59             }
    60         }
    61     }
    62 }
     
    3)AIO (Asynchronous I/O) 异步非阻塞I/O 
        不阻塞任何线程
     
    • 读完了再通知我
    • 不会加快IO,只是在读完后进行通知 
    • 使用回调函数,进行业务处理
     
     
     1 public static void main(String[] args) throws IOException {
     2  
     3     AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0000));
     4     server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
     5         final ByteBuffer buffer = ByteBuffer.allocate(1024);
     6  
     7         @Override
     8         public void completed(AsynchronousSocketChannel result, Object attachment) {
     9             System.out.println(Thread.currentThread().getName());
    10             Future<Integer> writeResult = null;
    11             try {
    12                 buffer.clear();
    13                 result.read(buffer).get(100, TimeUnit.SECONDS);
    14                 buffer.flip();
    15                 writeResult = result.write(buffer);
    16             } catch (InterruptedException | ExecutionException e) {
    17                 e.printStackTrace();
    18             } catch (TimeoutException e) {
    19                 e.printStackTrace();
    20             } finally {
    21                 try {
    22                     server.accept(null, this);
    23                     writeResult.get();
    24                     result.close();
    25                 } catch (Exception e) {
    26                     System.out.println(e.toString());
    27                 }
    28             }
    29         }
    30  
    31         @Override
    32         public void failed(Throwable exc, Object attachment) {
    33             System.out.println("failed: " + exc);
    34         }
    35     });
    36  
    37 }
     
     
     
  • 相关阅读:
    许可管理工具
    浅谈MapControl控件和PageLayoutControl控件
    通过Bresenham算法实现完成矢量线性多边形向栅格数据的转化
    四叉树算法原理与实现
    OC系列foundation Kit基础-NSNumber
    OC系列foundation Kit基础-NSdictionary
    OC系列foundation Kit基础-NSMutableArray
    OC系列foundation Kit基础-NSArray
    OC系列foundation Kit基础-NSMutableString
    OC系列foundation Kit基础-NSString
  • 原文地址:https://www.cnblogs.com/756623607-zhang/p/9181003.html
Copyright © 2011-2022 走看看