javaNio 学习笔记(一) 学习参考文档: http://tutorials.jenkov.com/java-nio/index.html 什么是javaNio java Nio是java new IO。是java1.4新增的API。它提供了另一种不同于标准IO的实现方式来实现IO 知其然知其所以然 为什么要使用java Nio? 弄懂了为什么要使用 Java NIO 也就是知道我们为啥要学NIO了。 首先NIO出现就是提供了替代标准IO的一种IO实现方式。那么为什么要替换标准IO呢? 我们来看下下面的例子: // server public class Bio { public static void main(String[] args) { try { ServerSocket server = new ServerSocket(2999); System.out.println("server 监听2999端口等待客户端连接" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant()); Socket socket = server.accept(); System.out.println("server 监听2999端口等待客户端接受数据" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant()); // 从套接字中获取输入流 InputStream inputStream = socket.getInputStream(); byte[] bytes = new byte[1024]; inputStream.read(bytes); System.out.println("get message from client: " + new String(bytes) + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant()); inputStream.close(); socket.close(); server.close(); } catch (IOException e) { e.printStackTrace(); } } } // client public class Client { public static void main(String[] args) { try { // 建立连接 System.out.println("客户端准备连接服务器 2999端口" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant()); Socket socket = new Socket("127.0.0.1", 2999); System.out.println("客户端连接服务器 2999端口" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant()); // 向socket写入数据 OutputStream outputStream = socket.getOutputStream(); System.out.println("客户端连接服务器开始写入数据" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant()); socket.getOutputStream().write("hi, be happy".getBytes("UTF-8")); System.out.println("客户端连接服务器开始写入完成" + Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant()); outputStream.close(); socket.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } 先启动server,然后再启动client(为了让结果比较清晰建议打断点运行),返回结果如下 // server 返回结果: server 监听2999端口等待客户端连接2020-06-11T14:35:58.428Z server 监听2999端口等待客户端接受数据2020-06-11T14:36:16.120Z get message from client: hi, be happy // client 返回结果 客户端准备连接服务器 2999端口2020-06-11T14:36:02.026Z 客户端连接服务器 2999端口2020-06-11T14:36:35.664Z 客户端连接服务器开始写入数据2020-06-11T14:36:40.984Z 客户端连接服务器开始写入完成2020-06-11T14:36:42.969Z 运行断点的时候会发现,当server执行到 server.accept() 和inputStream.read() 的时候程序会阻塞,让程序等待,这样会影响执行效率。这也就是为什么会有NIO来替代IO。先自己思考解决方案 如果是让我来解决这个问题,该如何处理呢? 可以开线程,每一个线程来处理一个client的连接。这样即使阻塞也是只阻塞当前线程。这样即使阻塞也只是阻塞当前线程,而不会对其他线程造成影响。当然这么做就会消耗系统资源,因为线程是有限的,我们不可能无限的开启线程,若客户端一直未连接就需要做超时处理,将线程关闭。 Java NIO是如何来做的? 这个问题可能需要等到学习完 java NIO 之后才可能回答得出来。那么下面我就开始学习Java NIO。java NIO简单导读 参考上面文档地址 传统 IO 是面向流的,而java NIO 则是面向channels 和buffers 的。数据都是从channel 中读取到buffer 或者从channel 中写入buffer 。java NIO 是非阻塞IO,即不会产生上面的问题。线程可以让channel (有的人叫通道)去读取buffer 中的数据,这个时候线程可以做其他事情。当数据层从channel 读取到buffer 的时候线程在继续处理这部分事情。对于写也是一样。Java NIO 还提供了一个selector 。selector 是一个对象,可以监控多个通道的事件(如:连接打开,数据到达等)。这样可以让单个线程监视多个channel java NIO 基本概念 java NIO主要的核心组件如下: Channels(通道、管道、频道) buffers(数据缓冲区) Selector(选择器,从导读的概念来看感觉有点像监听器) 当然java NIO还有一些其他组件,后面我会慢慢进行学习。 channel 和buffer 就可以理解潮汐车道俩头的地点。数据可以从频道(channel)中写入缓冲区(buffer). 也可以从缓冲区读取到频道中。 主要实现的管道类型 FileChannel DatagramChannel SocketChannel ServerSocketChannel 核心的缓冲区 ByteBuffer CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer 选择器 选择器的作用就是能让单个线程来处理多线程的事情。要使用选择器,需要注册频道。然后调用它的select()方法。此方法将阻塞,直到为其中一个已注册通道准备好事件为止。方法返回后,线程就可以处理这些事件。(有传入的连接,接收到的数据等等) 这些类型后续学习中我会进行练习并尽量做详细了解