简单了解一下Java 中的 NIO ,为什么是NIO ?
由于之前老的I/O类库是阻塞I/O,New I/O类库的目标就是要让Java支持非阻塞I/O,所以,更多的人喜欢称之为非阻塞I/O(Non-block I/O)
一,Java NIO
通道 Channel
我们说过,NIO 的核心就是通道和缓存区,所以它们的工作模式是这样的:
但是你要明白一点,通道和流一样都是需要基于物理文件的,而每个流或者通道都通过文件指针操作文件,这里说的「通道是双向的」也是有前提的,那就是通道基于随机访问文件『RandomAccessFile』的可读可写文件指针。
『RandomAccessFile』是既可读又可写的,所以基于它的通道是双向的,所以,「通道是双向的」这句话是有前提的,不能断章取义。
基本的通道类型有如下一些:
FileChannel
DatagramChannel
SocketChannel
ServerSocketChanne
SocketChannel和ServerSocketChannel
Socket类和ServerSocket类相对应,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。
低负载、低并发的应用程序可以选择同步阻塞I/O以降低编程复杂度;对于高负载、高并发的网络应用,需要使用NIO的非阻塞模式进行开发。
选择器 Selector
Selector 是 Java NIO 的一个组件,它用于监听多个 Channel 的各种状态,用于管理多个 Channel。但本质上由于 FileChannel 不支持注册选择器,所以 Selector 一般被认为是服务于网络套接字通道的。
而大家口中的「NIO 是非阻塞的」,准确来说,指的是网络编程中客户端与服务端连接交换数据的过程是非阻塞的。普通的文件读写依然是阻塞的,和 IO 是一样的,这一点可能很多初学者会懵,包括我当时也总想不通为什么说 NIO 的文件读写是非阻塞的,明明就是阻塞的。
创建一个选择器一般是通过 Selector 的工厂方法,Selector.open :
而一个通道想要注册到某个选择器中,必须调整模式为非阻塞模式
channel = SocketChannel.open();
channel.configureBlocking(false);
selector = Selector.open();
一个多路复用器Selector可以同时轮询多个Channel,由于JDK使用了epoll()代替传统的select实现,所以它并没有最大连接句柄1024/2048的限制。这也就意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端
channel = SocketChannel.open();
channel.configureBlocking(false);
selector = Selector.open();
channel.connect(new InetSocketAddress(robotIP, 7777));
channel.register(selector, 8);
int select = selector.select(reconnTime);
if (select > 0) {
Iterator ite = selector.selectedKeys().iterator();
key = (SelectionKey)ite.next();
ite.remove();
if (key.isConnectable()) {
channel = (SocketChannel)key.channel();
if (channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
}
你这个功能就不可能实现,不信你试试,尤其是加了选择器的客户端代码,更值得大家一行一行分析。提醒一点的是,大家应更多的关注于哪些方法是阻塞的,哪些是非阻塞的,这会有助于分析代码。
获取更多内容关注公众号: