【Java】 BIO与NIO以及AIO分析

一.BIO与NIO以及AIO的概念

  BIO是同步阻塞式的IO

  NIO是同步非阻塞的IO (NIO1.0,JDK1.4)

  AIO是非同步非阻塞的IO(NIO2.0,JDK1.7)

二.BIO简单分析

  1.简单分析

    BIO是阻塞的IO,原因在于accept和read会阻塞。所以单线程的BIO是无法处理并发的。

  2.案例

    服务端:

public class BioServer {
    public static void main(String[] args) throws IOException {//在开发中不要直接抛出去,有可能出现异常导致连接未关闭
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress("127.0.0.1",9999));

        byte[] b = new byte[1024];
        StringBuilder sb = new StringBuilder();
        System.out.println("服务端正在等待连接......");
        Socket socketAccept = serverSocket.accept();//这里会阻塞
        System.out.println("有客户端连接成功");
        while (true){
            System.out.println("等待消息......");
            int read = socketAccept.getInputStream().read(b);//这里会阻塞
            System.out.println("共读取了"+read+"个字节");

            String str = new String(b);
            sb.append(str);
            System.out.println("读取的数据内容为: " + sb);

        }
    }
}

    客户端:

public class BioClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        Scanner scanner = new Scanner(System.in);
        socket.connect(new InetSocketAddress("127.0.0.1",9999));
        while(true){
            System.out.println("请输入内容");
            String next = scanner.next();

            socket.getOutputStream().write(next.getBytes());
        }
    }
}

    测试如下:

    

  3.多线程下的BIO

    多线程的BIO是可以处理并发的,但频繁的创建线程,运行线程以及销毁线程无疑是非常消耗资源的(即便可以使用线程池限制线程数量,但海量并发时,BIO的方式效率相比于NIO还是太低了)

    下面是一个多线程的BIO案例:

      服务端:

public class BioServerMultiThread {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress("127.0.0.1",9999));
        System.out.println("服务端正在等待连接......");

        while (true){
            Socket socketAccept = serverSocket.accept();//这里会阻塞
            System.out.println("有客户端连接成功");

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        System.out.println("等待消息......");
                        String msg = "";
                        while (true){
                            byte[] b = new byte[1024];
                            int len = socketAccept.getInputStream().read(b);
                            if (len < 0){
                                continue;
                            }
                            msg = new String(b,0,len);
                            System.out.println(msg);
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

      客户端(创建多个客户端,代码相同):

public class BioClient1 {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        Scanner scanner = new Scanner(System.in);
        socket.connect(new InetSocketAddress("127.0.0.1",9999));
        String className = "这是来自"+Thread.currentThread().getStackTrace()[1].getClassName()+"的消息";
        while(true){
            System.out.println("请输入内容");
            String next = scanner.next();
            socket.getOutputStream().write(className.getBytes());
            socket.getOutputStream().write(next.getBytes());
        }
    }
}

      测试如下:

      

三.NIO简单分析

  NIO是非阻塞IO,其原因在于数据准备就绪后,由选择器通知给服务端,而在数据准备完毕之前,服务器无需等待。

  1.缓冲区

    在BIO操作中,所有的数据都是以流的形式操作的,而在NIO中,则都是使用缓冲区来操作。

    NIO中的缓冲区是Buffer类,它是java.nio包下的一个抽象类,详情可以查看JDK的API文档,例如下图

    

    打开Buffer类,可以看到如下图(其中带有的方法可以查看JDK文档)

    

  2.直接缓冲区和非直接缓冲区

    直接缓冲区是指将缓冲区建立在物理内存中,通过allocateDirect方法建立(效率高,但不安全)

    非直接缓冲区是指将缓冲区建立在JVM中,通过allocate方法建立(效率低,但安全)

  3.管道

    管道是NIO中传输数据的桥梁,它是java.nio包下的一个接口,若需查看其详细信息可以参考JDK的API文档,例如下图

    

  4.使用NIO实现文件拷贝两种方式案例

    直接缓冲区的方式:

    @Test
    public void test1() throws IOException {
        long statTime=System.currentTimeMillis();
        //创建管道
        FileChannel   inChannel=    FileChannel.open(Paths.get("E://test/aaa.txt"), StandardOpenOption.READ);
        FileChannel   outChannel=    FileChannel.open(Paths.get("E://test/bbb.txt"), StandardOpenOption.READ,StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //定义映射文件
        MappedByteBuffer inMappedByte = inChannel.map(FileChannel.MapMode.READ_ONLY,0, inChannel.size());
        MappedByteBuffer outMappedByte = outChannel.map(FileChannel.MapMode.READ_WRITE,0, inChannel.size());
        //直接对缓冲区操作
        byte[] dsf=new byte[inMappedByte.limit()];
        inMappedByte.get(dsf);
        outMappedByte.put(dsf);
        inChannel.close();
        outChannel.close();
        long endTime=System.currentTimeMillis();
        System.out.println("操作直接缓冲区耗时时间:"+(endTime-statTime));
    }

    非直接缓冲区的方式:

 @Test
    public void test2() throws IOException {
        long statTime=System.currentTimeMillis();
        // 读入流
        FileInputStream fst = new FileInputStream("E://test/bbb.txt");
        // 写入流
        FileOutputStream fos = new FileOutputStream("E://test/ccc.txt");
        // 创建通道
        FileChannel inChannel = fst.getChannel();
        FileChannel outChannel = fos.getChannel();
        // 分配指定大小缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        while (inChannel.read(buf) != -1) {
            // 开启读取模式
            buf.flip();
            // 将数据写入到通道中
            outChannel.write(buf);
            buf.clear();
        }
        // 关闭通道 、关闭连接
        inChannel.close();
        outChannel.close();
        fos.close();
        fst.close();
        long endTime=System.currentTimeMillis();
        System.out.println("操作非直接缓冲区耗时时间:"+(endTime-statTime));
    }

  5.选择器(Selector)

    它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接。使用Selector的好处在于: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销。详细用法可以参考JDK的API文档

    

四.AIO简单分析

  AIO(NIO2.0)和 NIO的主要区别是前者是异步的,而后者是同步的。

  同步:

    所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是事情必须一件一件地做,等前一件做完了才能做下一件事。

  异步:

    异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

   与NIO不同,当进行读写操作时,AIO只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。  即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。

原文地址:https://www.cnblogs.com/ywb-articles/p/11108413.html

时间: 2024-08-04 17:13:14

【Java】 BIO与NIO以及AIO分析的相关文章

[转帖]JAVA BIO与NIO、AIO的区别(这个容易理解)

JAVA BIO与NIO.AIO的区别(这个容易理解) https://blog.csdn.net/ty497122758/article/details/78979302 2018-01-05 11:26:13 涂有 阅读数 41728 文章标签: javaaiobionio 更多 分类专栏: java IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个Server

Java BIO、NIO与AIO的介绍(学习过程)

Java BIO.NIO与AIO的介绍 因为netty是一个NIO的框架,所以在学习netty的过程中,开始之前.针对于BIO,NIO,AIO进行一个完整的学习. 学习资源分享: Netty学习:https://www.bilibili.com/video/BV1DJ411m7NR?from=search&seid=8747534277052777648 Netty源码:https://www.bilibili.com/video/BV1cb411F7En?from=search&seid

Java BIO、NIO、AIO 学习

先来个例子理解一下概念,以银行取款为例: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写). 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API). 阻塞 : ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回). 非阻塞 : 柜台取款,取个号,然后坐在椅子上做其它事,等号广播会通知你办理,没到号你

【转】Java BIO、NIO、AIO 认知

摘要: 关于java的IO,我们很多人都停留在java原API的一些stream上面,那么在网络中提到的BIO.NIO.AIO等关键词,你是否明白这个词的含义,以及其基本的原理? 注:此文也是本搬砖者转自网络,觉得此问对三个类型的IO的形象讲解做的很好,所以翻出来和大家共同学习. 原创:http://stevex.blog.51cto.com/4300375/1284437 先来个例子理解一下概念,以银行取款为例: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读

Java BIO、NIO、AIO基础概念

引用别人的例子理解一下概念,以银行取款为例. 同步与异步:这两个概念与消息的通知机制有关,也就是同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者,. ① 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写). ② 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API). 阻塞与非阻塞:与程

【转】JAVA BIO与NIO、AIO的区别

Java中IO的模型分为三种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. BIO[同步阻塞] 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行. NIO[同步非阻塞] NIO本身是基于事

Java BIO、NIO、AIO

同步与异步 同步与异步的概念, 关注的是 消息通信机制 同步是指发出一个请求, 在没有得到结果之前该请求就不返回结果, 请求返回时, 也就得到结果了. 比如洗衣服, 把衣服放在洗衣机里, 没有洗好之前我们一直看着, 直到洗好了才拿出来晾晒. 异步是指发出一个请求后, 立刻得到了回应, 但没有返回结果. 这时我们可以再处理别的事情(发送其他请求), 所以这种方式需要我们通过状态主动查看是否有了结果, 或者可以设置一个回调来通知调用者. 比如洗衣服时, 把衣服放到洗衣机里, 我们就可以去做别的事情,

JAVA中IO技术:BIO、NIO、AIO

1.同步异步.阻塞非阻塞概念 同步和异步是针对应用程序和内核的交互而言的. 阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值. 由上描述基本可以总结一句简短的话,同步和异步是目的,阻塞和非阻塞是实现方式. 1 同步 指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪 自己上街买衣服,自己亲自干这件事,别的事干不了.

Java核心(五)深入理解BIO、NIO、AIO

导读:本文你将获取到:同/异步 + 阻/非阻塞的性能区别:BIO.NIO.AIO 的区别:理解和实现 NIO 操作 Socket 时的多路复用:同时掌握 IO 最底层最核心的操作技巧. BIO.NIO.AIO 的区别是什么? 同/异步.阻/非阻塞的区别是什么? 文件读写最优雅的实现方式是什么? NIO 如何实现多路复用功能? 带着以上这几个问题,让我们一起进入IO的世界吧. 在开始之前,我们先来思考一个问题:我们经常所说的"IO"的全称到底是什么? 可能很多人看到这个问题和我一样一脸懵