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()方法。此方法将阻塞,直到为其中一个已注册通道准备好事件为止。方法返回后,线程就可以处理这些事件。(有传入的连接,接收到的数据等等)
这些类型后续学习中我会进行联系并尽量做详细了解