美文网首页
第11讲 | Java提供了哪些IO方式? NIO如何实现多路复

第11讲 | Java提供了哪些IO方式? NIO如何实现多路复

作者: governlee | 来源:发表于2019-04-21 23:47 被阅读0次

    Java IO 方式有很多种,基于不同的 IO 抽象模型和交互方式,可以进行简单区分。

    • 同步、阻塞的方式(BIO): 传统的 java.io 包,它基于流模型实现,比如 File 抽象、输入输出流等.在读取输入流或者写入输出流时,在读、写动作完成之前,线程会一直阻塞在那里。java.io 包的好处是代码比较简单、直观,缺点则是 IO 效率和扩展性存在局限性,容易成为应用性能的瓶颈。

    人们也把 java.net 下面提供的部分网络 API,比如Socket、ServerSocket、HttpURLConnection 也归类到同步阻塞 IO ,因为网络通信同样是 IO 行为。

    • Java1.4引入NIO 框架(java.nio 包),提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层的高性能数据操作方式。

    • Java7引入了异步非阻塞 IO 方式,也有很多人叫它 AIO(Asynchronous IO/NIO2)。异步 IO 操作基于事件和回调机制。

    区分同步或异步(synchronous/asynchronous)。简单来说,同步是一种可靠的有序运行机制,当我们进行同步操作时,后续的任务是等待当前调用返回,才会进行下一步。;而异步则相反,其他任务不需要等待当前调用返回,通常依靠事件、回调等机制来实现任务间次序关系。

    阻塞与非阻塞(blocking/non-blocking)。在进行阻塞操作时,当前线程会处于阻塞状态,无法从事其他任务,只有当条件就绪才能继续,比如 ServerSocket 新连接建立完毕,或数据读取、写入操作完成;而非阻塞则是不管 IO 操作是否结束,直接返回,相应操作在后台继续处理。

    • IO 不仅仅是对文件的操作,网络编程中,比如Socket 通信,都是典型的 IO 操作目标。
    • 输入流、输出流(InputStream/OutputStream)是用于读取或写入字节的,例如操作图片文件。
    • Reader/Writer 则是用于操作字符,增加了字符编解码等功能,适用于类似从文件中读取或者写入文本信息。本质上计算机操作的都是字节,不管是网络通信还是文件读取,Reader/Writer 相当于构建了应用逻辑和原始数据之间的桥梁。
    • BufferedOutputStream 等带缓冲区的实现,可以避免频繁的磁盘读写,进而提高 IO 处理效率。这种设计利用了缓冲区,将批量数据进行一次操作,但在使用中千万别忘记flush。
    • 很多 IO 工具类都实现了 Closeable 接口,因为需要进行资源的释放。打开 FileInputStream,它就会获取相应的文件描述符(FileDescriptor),需要利用 try-with-resource,try-finally等机制保证 FileInputStream 被明确关闭,进而相应文件描述符也会失效,否则将导致资源无法被释放。
    image.png

    NIO 的主要组成部分

    • Buffer,高效的数据容器,除了布尔类型,所有原始数据类型相应的Buffer.

    • Channel,类似在 Linux 之类操作系统上看到的文件描述符,是 NIO 中被用来支持批量式 IO 操作的一种抽象。
      File 或者 Socket,通常被认为是比较高层次的抽象,而 Channel 则是更加操作系统底层的一种抽象,这也使得 NIO 得以充分利用现代操作系统底层机制,获得特定场景的性能优化。不同层次的抽象是相互关联的,我们可以通过 Socket 获取channel,反之亦然。

    • Selector,是 NIO 实现多路复用的基础,它提供了一种高效的机制,可以检测到注册在 Selector 上的多个channel,是否有channel处于就绪状态,进而实现了单线程对多 Channel 的高效管理。

    • Selector 同样是基于底层操作系统机制,不同模式、不同版本都存在区别。linux中依赖于epoll。

    NIO 能解决什么问题?

    设想,我们需要实现一个服务器应用,只简单要求能够同时服务多个客户端请求即可。

    使用 java.io 和 java.net 中的同步、阻塞式API可以简单实现:

    public class DemoServer extends Thread {
        private ServerSocket serverSocket;
        public int getPort() {
            return  serverSocket.getLocalPort();
        }
        public void run() {
            try {
                // 绑定端口0
                serverSocket = new ServerSocket(0);
                while (true) {
                    // 阻塞等待客户端连接
                    Socket socket = serverSocket.accept();
                    RequestHandler requestHandler = new RequestHandler(socket);
                    requestHandler.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (serverSocket != null) {
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    ;
                }
            }
        }
        public static void main(String[] args) throws IOException {
            DemoServer server = new DemoServer();
            server.start();
            // 模拟了一个简单的客户端,只进行连接、读取、打印
            try (Socket client = new Socket(InetAddress.getLocalHost(), server.getPort())) {
                BufferedReader bufferedReader = new BufferedReader(new                   InputStreamReader(client.getInputStream()));
                bufferedReader.lines().forEach(s -> System.out.println(s));
            }
        }
     }
    // 简化实现,不做读取,直接发送字符串
    class RequestHandler extends Thread {
        private Socket socket;
        RequestHandler(Socket socket) {
            this.socket = socket;
        }
        @Override
        public void run() {
            try (PrintWriter out = new PrintWriter(socket.getOutputStream());) {
                out.println("Hello world!");
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     }
    
    

    相关文章

      网友评论

          本文标题:第11讲 | Java提供了哪些IO方式? NIO如何实现多路复

          本文链接:https://www.haomeiwen.com/subject/uvkjgqtx.html