NIO描述
什么是NIO?
NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
传统的IO包提供的是同步阻塞IO,而Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。数据由缓冲区进行交互。非阻塞的核心就是通道和缓冲区,当 IO 事件就绪时,可以通过写道缓冲区,保证 IO 的成功,而无需线程阻塞式地等待。
Java NIO: Selectors(选择器)
Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
NIO和IO的主要区别
IO |
NIO |
面向流 |
面向缓冲区 |
阻塞IO |
非阻塞IO |
无 |
选择器 |
API用法
/** * Buffer类的子类 * ByteBuffer(用的最多) * CharBuffer * ShortBuffer * IntBuffer * LongBuffer * FloatBuffer * DoubleBuffer * 没有 BooleanBuffer * * Buffer类中四个比较重要的参数: * mark = -1; 标记 * position 缓冲区正在操作的位置,默认从0开始 * limit 缓冲区可用大小,默认1024,缓冲创建时,limit 的值等于 capacity 的值, * 假设我们创建的时候给limit设值为100,那么缓冲区容量是1024,但是实际可用容量是100 * capacity 缓冲区最大容量,这一容量在缓冲区创建时被设定,并且永远不能被改变。 * * 子类中两个比较重要的方法(父类并没有这两个方法) * put:往buffer中存放数据 * get:获取数据 */ public class NioDemo { public static void main(String[] args) { //初始化ByteBuffer大小,调用这个方法产生的是非直接缓冲区,效率慢但是安全 ByteBuffer allocate = ByteBuffer.allocate(1024); System.out.println(allocate.position());//0 System.out.println(allocate.limit());//1024 System.out.println(allocate.capacity());//1024 System.out.println("---------放入数据----------"); //放入数据 allocate.put("abc".getBytes()); System.out.println(allocate.position());//3 //limit表示整个Buffer可用的大小,就算之前用过大小还是不变 System.out.println(allocate.limit());//1024 System.out.println(allocate.capacity());//1024 System.out.println("--------读取值-----------"); /** * 如果要读取值,必须得开启读取模式不然会报错, * java.nio.BufferUnderflowException * 因为之前position已经从3开始了,所以这里是读不到的,需要 * 把position重置为0 * System.out.println(allocate.position());//3 * System.out.println(allocate.limit());//1024 * System.out.println(allocate.capacity());//1024 * byte[] bytes = new byte[allocate.limit()]; * allocate.get(bytes); * System.out.println(new String(bytes,0,bytes.length)); */ //当读取值的时候,limit的值会和读取的值的长度一样 allocate.flip(); System.out.println(allocate.position());//0 System.out.println(allocate.limit());//3 System.out.println(allocate.capacity());//1024 byte[] bytes = new byte[allocate.limit()]; allocate.get(bytes); System.out.println(new String(bytes,0,bytes.length));//abc // allocate.get(bytes); // System.out.println(new String(bytes,0,2));//ab /** * 当上面第一次读完的时候position已经变成了3,所以第二次读取的时候, * 如果不把position重置为0,还是会报错,需要添加一个方法 * allocate.rewind() */ System.out.println("--------清空缓存区-----------"); //当清空缓存的时候,只是把界限变成了一开始的状态,但是值还是存在, //数据被遗忘 allocate.clear(); System.out.println(allocate.position());//0 System.out.println(allocate.limit());//1024 System.out.println(allocate.capacity());//1024 System.out.println((char)allocate.get());// a } }