NIO
java 1.4版本引入,给予缓冲区面 向通道的io操作
bio | nio |
---|
面向流 | 面向缓冲区(buffer) |
阻塞io | 非阻塞io |
同步 | 同步 |
无 | Selector(选择器) |
缓冲区:是一个特定数据类型的容器,有java.nio 包定义,所有的缓冲区都是Buffer抽象类的子类 子类:ByteBuffer CharBuffer ShortBuffer IntBuffer LongBuffer FloatBuffer DoubleBuffer Buffer次要用于和NIO通道进行通信,数据从通道读入到缓冲区,再从缓冲区读取到通道 Buffer就像是一个数据能够保留多个类型雷同的数据 根本属性: 1.容量(capacity):示意缓冲区的最大容量 一旦创立不能批改 2.限度(limit):第一个不可读的索引,即位于limit前面的数据不可读 3.地位(position):下一个要读取或写入数据的索引 4.flip:将此时的position设为limit,position置为0 - 个别是从inputChannel将数据读入到buffer 而后将buffer flip后 为了从buffer中读取数据到 outputChannel 5.标记(mark)和复原(reset):标记是一个索引,通过Buffer.mark()指定一个特定的地位,应用reset办法能够复原到这个地位
- 间接缓冲区:程序间接操作物理映射文件
- 非间接缓冲区:jvm - 操作系统 - 物理内存
Channel:相似于流,然而Channel不能间接拜访数据,只能与缓冲区进行交互通道 主体实现类 1.FileChannel:用于读取 写入 映射和操作文件的通道 2.DataGramChannel:通过UDP读取网络中的数据通道 3.SocketChannel:通过Tcp读写通道的数据 4.ServerSocketChannel:能够监听新进入的Tcp连贯,对每一个新连贯创立一个SocketChannel 提供getChannel()办法的类 1.FileInputStream 2.FileOutputStream 3.RandomAccessFile 4.Socket 5.ServerSocket 6.DataGramSocket 通道工夫传输 1.transferFrom() 2.transferTo()
- 扩散读取(Scatter):将一个
Channel
中的数据扩散贮存到多个Buffer
中 - 汇集写入(Gather):将多个
Buffer
中的数据写入同一个Channel
中
Selector个别被称为选择器,也被称为多路复用器.用于查看一个或多个通道是否处于可读可写如此能够实现一个线程治理多个Channel 应用Selector带来的益处有:应用更少的线程来解决Channel,能够避免上下文切换带来的性能小号 能够被抉择(多路复用)的Channel都继承自SelectableChannel SelectableChannel || AbstractSelectableChannel || || || DataGramChannel SocketChannel ServerSocketChannel 所以FileChannel不适应与Selector,即不能切换为非阻塞模式 Selector应用根本步骤 1.创立Selector: Selector selector = Selector.open(); 2.设置为非阻塞为:channel.configureBlocking(false); 3.注册Channel到Selector: /** * 参数-1:要注册到的多路复用器 * 参数-2:是一个"interest汇合",即要监听事件的汇合(有以下四种) * OP_CONNECT 连贯 * OP_ACEEPT 接管 * OP_READ 读 * OP_WRITE 写 */ SelectionKey key = channel.register(selector,SelectionKey.OP_READ); 如果要监听多种事件如下: SelectionKey key = channel.register(selector,SelectionKey.OP_CONNECT | SelectionKey.OP_READ); 4.而后就 连贯就绪 | 接管就绪 | 读就绪 | 写就绪
Selector次要办法
办法 | 形容 |
---|
Set<SelectKey> keys() | 返回所有SelectionKey 汇合,代表 注册在这个Selector上 的Channel |
Set<SelectKey> selectedKeys() | 返回已抉择了的(即有io操作的)SelectionKey |
int select() | 监控所有注册了的Channel ,如果有须要 io的操作时会将对应的selectKey 退出到 selectedKeys 汇合中,返回的则是被抉择 (有io操作的)Channel 数量,这个操作时阻 塞的即只有被抉择的Channel 数量>=1才 返回 |
int select(timeout) | 有超时时长,始终没有io操作的Channel 呈现, 达到timeout呈现的工夫后将主动返回 |
int selectNow() | 无阻塞 立刻返回 |
Selector wakeUp() | 使正在select() 立刻返回 |
void close() | 敞开 |
SelectionKey次要办法
SelectionKey
示意Channel
和Selector
之间的关系,Channel
向Selector
注册就会产生一个SelectionKey
办法 | 形容 |
---|
int interestOps() | 感兴趣事件的汇合 boolean isInterested = interestSet & SelectionKey.OP_CONNECT ... |
int readyOps() | 获取通道筹备好就绪的操作 |
SelectableChannel channel() | 获取注册通道 |
Selector selector() | 获取选择器 |
boolean isConnectable() | 检测Channel 中是否有连贯事件就绪 |
boolean isAcceptable() | 检测Channel 中是否有接管事件就绪 |
boolean isReadaable() | 检测Channel 中是否有读事件就绪 |
boolean isWriteable() | 检测Channel 中是否有写事件就绪 |
Object attach() | 将一个对象附着到SelectionKey 上, 次要是一些用于标识的信息 |
Object attachment() | 获取注册信息 也能够在Channel 注册的时候附着信息 SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject); |
void cancel() | 申请勾销此键的通道到其选择器的注册 |
package com.yuan.nio.selector;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;public class NioServer { public static void main(String[] args) throws IOException { //创立服务端通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //非阻塞模式 serverSocketChannel.configureBlocking(false); //绑定端口 serverSocketChannel.bind(new InetSocketAddress(9021)); //创立选择器 Selector selector = Selector.open(); //注册 接管 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //有一个事件时就操作 while (selector.select() > 0) { //获取事件汇合 Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); //如果是接管就绪 if (selectionKey.isAcceptable()) { //获取客户端连贯 SocketChannel socketChannel = serverSocketChannel.accept(); //切换成非阻塞 socketChannel.configureBlocking(false); //注册在多路复用器上 读 socketChannel.register(selector, SelectionKey.OP_READ); //读事件 } else if (selectionKey.isReadable()) { //获取客户端连贯 SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); //设置缓存 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); int len = 0; while (-1 != (len = socketChannel.read(byteBuffer))) { byteBuffer.flip(); System.out.println(new String(byteBuffer.array(),0,len)); byteBuffer.clear(); } //申请勾销此键的通道在其选择器的注册,也就是 selector.select();的数量 -1 selectionKey.cancel(); socketChannel.close(); } } iterator.remove(); } }}