1. NIO
NIO是Non-blocking IO,与传统IO的区别是不会阻塞线程,在多线程中,利用传统IO处理时,遇到网络延迟较高的场景时,阻塞线程的情况比较严重,那么对线程造成的资源浪费线程就比较多了,此时若是利用NIO的话,则能避免这种情况,而NIO中三个重要概念是Buffer,Channel,Selector,用图能理解三者的关系。
1.1 Buffer
可以简单将Buffer理解为一个数组,而这个数组元素的操控以及访问由position,limit,capacity三个变量控制。其中, 从写模式切换到读模式时,需要用flip()函数,改变position和limit的位置才能实现读取数据。
position:下一个操作元素的位置
limit:不可操作元素的位置
capacity:容量
1.2 Selector用法
- 打开selector
- 注册Channel
- 获取Channel
① 获取Channel;准备好数据的Channel个数(阻塞等待)
② 通过SelectorKeys来获取Channel集合
③ 迭代获取每个Channel - 移除处理完的Channel12345678910111213141516171819202122232425262728293031// ① 打开selectorSelector selector = Selector.open();channel.configureBlocking(false);// ② 注册ChannelSelectionKey key = channel.register(selector, SelectionKey.OP_READ);while(true) {//③ 获取Channel;准备好数据的Channel个数(阻塞等待)int readyChannels = selector.select();if(readyChannels == 0) continue;//④ 通过SelectorKeys来获取Channel集合Set<SelectionKey> selectedKeys = selector.selectedKeys();// ⑤ 迭代获取每个ChannelIterator<SelectionKey> keyIterator = selectedKeys.iterator();while(keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if(key.isAcceptable()) {// a connection was accepted by a ServerSocketChannel.} else if (key.isConnectable()) {// a connection was established with a remote server.} else if (key.isReadable()) {// a channel is ready for reading} else if (key.isWritable()) {// a channel is ready for writing}// ⑥ 移除处理完的ChannelkeyIterator.remove();}}
2. NIO数据访问方式
传统文件的访问需要从磁盘上加载到内核空间,再有内核空间加载到用户空间,而NIO的两种数据访问方式都能优化这个问题。
① FileChannel.transferTo/transferFrom:使得数据直接从磁盘加载到内核空间,数据直接在内核空间移动即可
② FileChannel.map:将文件映射为内存区域,直接访问这个内存区域就能操作文件,省去了数据从内核空间复制到用户空间的损耗。