NIO是什么
- JDK1.4以后提供的新的IO操作API,可以叫做new IO(新的IO)或者说Non Blocking IO(非阻塞的IO)。
- NIO面向缓冲区(Buffer),基于通道(Channel)的IO操作,多通道之间使用选择器(Selectors)读写操作更加高效。
传统IO和NIO的区别
IO | NIO |
---|---|
面向流(Stream Oriented) | 面向缓存区(Buffere Oriented) |
阻塞IO(Blocking IO) | 非阻塞IO(Non Blocking IO) |
无 | 选择器(Select) |
流和缓冲区
数据流流动和分批次流动的区别,举个例子,把数据比作人群,数据流就是人流,缓冲区就是高铁或者飞机,两地之间人员流动,肯定是高铁或飞机快。
阻塞和非阻塞
- 阻塞/非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
- 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
- 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
同步和异步
- 同步/异步关注的是消息通信机制 (synchronous communication/ asynchronous communication) 。
- 所谓同步,就是在发出一个调用时,在没有得到结果之前, 该调用就不返回。
- 异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果
举个例子,你去买饭,同步阻塞就是你自己去排队买饭;异步阻塞就是你让别人帮你去排队买饭;同步非阻塞就是你去买饭,付完款等待叫号;异步非阻塞就是你叫了个外卖,外卖人员去了叫号取餐。
快速上手
先写个demo,对比一下io和nio两种方式拷贝一个文件
@Test
void io和nio复制文件对比() throws IOException {
//文件大小 64M
//mac pro电脑
String sourcePath = "/Users/liupeng/IdeaProjects/test/1.bin";
String desPath = "/Users/liupeng/IdeaProjects/test/2.bin";
File source = new File(sourcePath);
File des = new File(desPath);
if (!des.exists()) {
des.createNewFile();
}
long start1 = System.currentTimeMillis();
copyFileIO(source, des);
long end1 = System.currentTimeMillis();
System.out.println("io方式:" + (end1 - start1) + "毫秒");
long start2 = System.currentTimeMillis();
copyFileNIO(source, des);
long end2 = System.currentTimeMillis();
System.out.println("nio方式:" + (end2 - start2) + "毫秒");
//输出:
//io方式:9710毫秒
//nio方式:240毫秒
}
private void copyFileIO(File source, File des) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(des));
//将数据源读到的内容写入目的地--使用数组
byte[] bytes = new byte[1024 * 1024];
int len;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
}
private void copyFileNIO(File source, File des) throws IOException {
RandomAccessFile read = new RandomAccessFile(source, "rw");
RandomAccessFile write = new RandomAccessFile(des, "rw");
FileChannel readChannel = read.getChannel();
FileChannel writeChannel = write.getChannel();
// ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024);//1M缓冲区 分配到jvm内存
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024 * 1024);//1M缓冲区 直接分配到os内存
while (readChannel.read(byteBuffer) > 0) {
byteBuffer.flip();
writeChannel.write(byteBuffer);
byteBuffer.clear();
}
writeChannel.close();
readChannel.close();
}
NIO主要的三个概念
- 缓冲区 Buffer
- 通道 Channel
- 选择器 Selector
假如把数据流比作人流,可以理解为,通道就是火车轨道,缓冲区就是高铁,指挥中心就是选择器。