A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 大蓝鲸Java 于 2017-12-1 12:32 编辑

【南京校区】关于BIO,NIO,AIO的底层探讨
BIO : blocking IO 普通的IO
NIO : Non-blocking IO (new IO)  JDK 1.4 出现的
NIO2: NIO二代,又名 AIO.        JDK1.7以后出现的

NIO 跟 IO  相同的 都是读写操作.
不同的就是读写的方式是不一样的

IO 读写是面向于流来实现的

NIO 读写是面向于通道,面向缓冲区的. 提高了我们程序的效率
        缓冲区: ByteBuffer
                        ShortBuffer
                        IntBuffer
                        LongBuffer
                        FloatBuffer
                        DoubleBuffer
                        CharBuffer
        除了 boolean,其他7种基本数据类型都有其对应的缓冲区
        其中ByteBuffer是用的最多的.
        因为IO 操作的更多的是字节数据.

关于NIO学习,最重要的:
        1,缓冲区
        2,通道
        3,选择器

1,缓冲区:
        在底层其实就是一个数组.
                capacity: 容量
                limit:可操作到哪个索引
                position:当前准备操作的索引
                mark:相当于一个标记,用来记录当前position的值
                reset:如果position的值发生变化了,那么通道reset可以反馈mark记录的那个值

                //测试缓冲区代码
                        // 创建一个缓冲区
                        ByteBuffer buff = ByteBuffer.allocate(1024);
                        // 因为此时缓冲区正准备往里存数据

                        // 所以容量为1024
                        System.out.println(buff.capacity());// 1024
                        // 可以被使用1024
                        System.out.println(buff.limit());// 1024
                        // 当前要往0索引存
                        System.out.println(buff.position());// 0

                        buff.put("abcde".getBytes());
                        // 所以容量为1024
                        System.out.println(buff.capacity());// 1024
                        // 可以被使用1024
                        System.out.println(buff.limit());// 1024
                        // 当前要往0索引存
                        System.out.println(buff.position());// 3

                        buff.flip();// 切换读写模式
                        // 要开始往从这个缓冲区中取数据了
                        // 容量为1024
                        System.out.println(buff.capacity());// 1024
                        // 因为只存了3个字节,所以可以被操作的索引就是3
                        System.out.println(buff.limit());// 3
                        // 当前要从0索引开始读了.
                        System.out.println(buff.position());// 0
                        buff.mark();
                        byte[] bys = new byte[2];
                        buff.get(bys);// 读了两个字节
                        System.out.println(new String(bys));
                        System.out.println(buff.capacity());// 1024
                        // 因为只存了5个字节,所以可以被操作的索引就是5
                        System.out.println(buff.limit());// 5
                        // 当前要从2索引开始读了.
                        System.out.println(buff.position());// 2
                        System.out.println("--------------------------");
                        buff.reset();
                        buff.get(bys);// 读了两个字节
                        System.out.println(new String(bys));
                        System.out.println(buff.capacity());// 1024
                        // 因为只存了5个字节,所以可以被操作的索引就是5
                        System.out.println(buff.limit());// 5
                        // 当前要从2索引开始读了.
                        System.out.println(buff.position());// 2
2,通道
                FileChannel        专门用于本地文件数据传输
                SocketChannel         用于TCP
                ServerSocketChannel 用于TCP
                DatagramChannel        用于UDP

                以 FileInputStream 为例,获取一个通道.
                        FileInputStream fis = new FileInputStream("a.txt");
                        fis.getChannel(); //获取一个通道
                        FileOutputStream fos = new FileOutputStream("copy.avi");
                        fos.getChannel();// 获取一个通道               
                利用通道,进行复制
                示例代码:
                        FileInputStream fis = new FileInputStream("数据源");
                                FileOutputStream fos = new FileOutputStream("目的地");
                                FileChannel inChannel = fis.getChannel();
                                FileChannel outChannel = fos.getChannel();
                                ByteBuffer buffer = ByteBuffer.allocate(8192);
                                while ((inChannel.read(buffer)) != -1) {
                                        buffer.flip();
                                        outChannel.write(buffer);
                                        buffer.clear();
                                }
                                inChannel.close();
                                outChannel.close();
                                fis.close();
                                fos.close();
               
3,到这里大家不仅疑惑,BIO,和NIO并没有体现出NIO的效率高的问题
        这个是因为,缓冲区又分为:直接缓冲区,非直接缓冲区        
        在上面的案例中,我们是直接 new 出来的数组.所以该数组在我们内存的堆中.
        又得引出一个新的内容:
        非直接缓冲区:把缓冲区创建在JVM虚拟机中.多了一个拷贝的操作
        直接缓冲区:把缓冲区直接创建在内存中,不归虚拟机管了.

        所以如果想利用NIO 提高读写的效率,那么就要结合直接缓冲区的操作
        FileChannel inchannel = FileChannel.open(Paths.get("数据源), StandardOpenOption.READ);
        FileChannel outchannel = FileChannel.open(Paths.get("目的地"),StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
                        
        //底层创建一个直接缓冲区.用这个缓冲区在通道进行传输
        inchannel.transferTo(0, inchannel.size(), outchannel);
        inchannel.close();
        outchannel.close();

        总结:
                通道就是用来连接数据源和目的地的.本身不传递数据,是通过通道里面的缓冲区进行传输的
                缓冲区分直接缓冲区和非直接缓冲区
                其中如果想提高效率,那么可以使用直接缓冲区,将缓冲区创建在系统本地物理内存,也就是在JVM虚拟机之外.


13 个回复

倒序浏览
点个赞!
回复 使用道具 举报
郭俊峰老师 来自手机 高级黑马 2017-12-1 12:19:21
藤椅
对底层有一定研究啊
回复 使用道具 举报
王哈哈 来自手机 中级黑马 2017-12-1 12:58:20
板凳
真的强!
回复 使用道具 举报
点个赞
回复 使用道具 举报
大蓝鲸Java 来自手机 中级黑马 2017-12-1 12:58:46
地板
自己顶自己
回复 使用道具 举报
唐杰 中级黑马 2017-12-1 13:01:07
7#
666,学习了。这解析很透彻。
回复 使用道具 举报
大蓝鲸Java 来自手机 中级黑马 2017-12-1 13:01:09
8#
谢谢各位,南京校区教研部会写出更多的干货。
回复 使用道具 举报
379177926 来自手机 中级黑马 2017-12-1 13:05:03
9#
nio面试的时候还是很喜欢问的
回复 使用道具 举报
{:8_474:}{:8_474:}
回复 使用道具 举报
还属于小白。。。
回复 使用道具 举报
海域王魂 来自手机 初级黑马 2017-12-1 13:21:57
12#
牛逼 虽然不会Java 但是感觉好厉害的样子
回复 使用道具 举报
@狂奔 来自手机 中级黑马 2017-12-1 13:37:36
13#
技术大牛,低层了解得好深。
回复 使用道具 举报
小许同学 来自手机 初级黑马 2017-12-1 13:47:46
14#
厉害厉害!!!!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马