zoukankan      html  css  js  c++  java
  • 01_NIO基本概念

    【NIO的几个概念】

    Buffer(缓冲区)

    Channel(通道,管道)

    Selector(选择器,多路复用器)

    【Buffer】

    Buffer是一个对象,它包括一些要写入或者要读取的数据。在NIO类库中加入Buffer对象,是NIO与原来BIO的一个重要区别。

    在面向流的BIO中,可以将数据直接写入或读取到Stream对象中,在NIO库中,所有的数据都是用缓冲区Buffer处理的(读、写)。

    缓冲区实质上是一个数组,通常它是一个字节数组(ByteBuffer),也可以使用其他类型的数组,这个数组为缓冲区提供了数据的访问读写等操作属性,如位置、容量、上限等概念(参考API文档)。

    Buffer类型:最常用的是ByteBuffer,实际上每一种java基本类型都对应了一种缓冲区(除了Boolean类型)

    ByteBuffer

    CharBuffer

    ShortBuffer

    IntBuffer

    LongBuffer

    FloatBuffer

    DoubleBuffer

     【Buffer入门实例1——几个常用方法】

    public class TestBuffer {
        
        public static void main(String[] args) {
            //Buffer基本操作
            //创建指定长度的缓冲区
            IntBuffer buf = IntBuffer.allocate(10);
            buf.put(66);   //position位置:0 -> 1
            buf.put(77);   //position位置:1 -> 2
            buf.put(88);   //position位置:2 -> 3
            System.out.println("【当前buf状态】:"+buf);
            //flip()把位置复位为0,也就是position位置 : 3 ->0
            buf.flip();
            System.out.println("使用flip()复位【当前buf状态】:"+buf);
            System.out.println("容量为:"+buf.capacity());
            System.out.println("限制为:"+buf.limit());
            
            System.out.println("获取下标为1的元素"+buf.get(1));
            System.out.println("get(index)方法,position位置不改变:"+buf);
            
            for(int i=0; i<buf.limit(); i++){
                //调用get()方法会使得buffer的缓冲区位置(position+1)向后递增一位
                System.out.print(buf.get()+"	");
            }
            System.out.println("
    buf对象遍历之后为【当前buf状态】:"+buf);    
        }
        
    }

    【运行结果】

     

     【Buffer实例2——wrap()方法】

    public static void main(String[] args) {
            /**
             * wrap方法的使用
             * wrap方法会包裹一个数组:一般这种用法不会先初始化缓冲对象的长度,因为没有意义,最后还会别wrap所包裹的数组覆盖掉。
             * 并且wrap方法修改缓冲区对象的时候,数组本身会跟着变化
            **/
            int arr[] = new int[]{3,6,9};
            IntBuffer buf1 = IntBuffer.wrap(arr);
            System.out.println(buf1);
            
            IntBuffer buf2 = IntBuffer.wrap(arr,0,2);
            //这样使用表示容量为数组arr的长度,但是可操作的元素只有实际进入缓冲区的元素长度
            System.out.println(buf2);
        }

    【运行结果】

     【buffer实例3——其他方法】

        public static void main(String[] args) {
            IntBuffer buf1 = IntBuffer.allocate(10);
            int[] arr = new int[]{2,5,8};
            buf1.put(arr);
            System.out.println("【当前buf1状态】:"+buf1);
            
            //一种复制方法
            IntBuffer buf2 = buf1.duplicate();
            System.out.println("【当前buf2状态】:"+buf2);
            
            buf1.flip();
            System.out.println("buf1的可读数据:"+buf1.remaining());
            
            int[] arr2 = new int[buf1.remaining()];
            //将缓冲区的数据放入到arr2数组中
            buf1.get(arr2);
            for(int i : arr2){
                System.out.print(Integer.toString(i) + ",");
            }
        }

    【运行结果】

    【channel】

    channel(通道),就像自来水管一样,网络数据通过channel读取和写入,通道与流的不同之处是:通道是双向的,而流只是一个方向上移动(一个流必须是InputStream或OutputStream的子类),而通道可以用于读、写或者二者同时进行,最关键的是可以与多路复用器(Selector)结合起来,有多种的状态位置,方便多路复用器去识别。

    事实上通道分为两大类:

    1.用于网络读写——SelectorChannel

    2.用于文件操作——FileChannel

    一般使用的[ SocketChannel ] 和 [ ServerSocketChannel ] 都是SelectorChannel的子类。

    【Selector】

    Select(多路复用器),是NIO的基础,非常重要,Selector提供选择已经就绪的任务的能力。

    简单说,就是Selector会不断地轮询注册在其上的通道(Channel),如果某个通道发生了读写操作,这个通道就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以取得就绪的Channel集合,从而进行后续的IO操作。

    一个Selector可以负责成千上万的Channel通道,没有上限,这也是JDK使用了epoll代替了传统的Selector实现,获得连接句柄没有限制,这也就以为着我们只要一个线程负责Selector的轮询,就可以接入成千上万的客户端,这是JDK NIO库的巨大进步。

    Selector线程就类似一个管理者(Master),管理了成千上万个通道,然后轮询那个管道的数据已经准备好,通知cpu执行IO的读取或写入操作。

    Selector模式:当IO事件(管道)注册到选择器以后,selector会分配给每个管道一个key值,相当于标签。Selector选择器是以轮询的方式进行查找注册的所有IO事件(管道),当我们的IO事件(管道)准备就绪后,Selector就会识别,会通过key值来找到对应的管道,进行相关的数据操作(即从管道里读或写操作,写到我们的缓冲区中)。

    每个Channel(管道)都会对Selector进行不同的时间基础,以便选择器查找:

      SelectionKey.OP_CONNECT

      SelectionKey.OP_ACCEPT

      SelectionKey.OP_READ

      SelectionKey.OP_WRITE

  • 相关阅读:
    2018-2019-1 20165313 20165212 20165222 实验二 固件程序设计
    2018-2019-1 20165313 20165212 2016522 实验一 开发环境的熟悉
    课程总结
    2017-2018-2 20165222 实验五《网络编程与安全》实验报告
    2017-2018-2 20165222实验四《Android程序设计》实验报告
    20165222 第十周课下补做
    20165222 实验三 敏捷开发与XP实践
    各种树
    【面试】MySQL
    Redis
  • 原文地址:https://www.cnblogs.com/HigginCui/p/8644629.html
Copyright © 2011-2022 走看看