您好,我是湘王,这是我的慕课手记,欢迎您来欢迎您再来

为了解决标准Java I/O令人难以忍受的效率问题,从JDK1.4开始,NIO出现了(Non-blocking I/O,官方称之为New I/O)NIO不但新增加了许多全新的类,而且还对原来的很多类进行了改写之所以是NIO是因为使用它的场景众多,譬如开发中必不可少的Tomcat以及大名鼎鼎的Netty,而Netty更是把NIO发挥到了极致成为了RPC技术事实上的标准所以它在JDK1.7中又升级为了AIONIO2)。

NIO主要有三大核心部分

Channel(通道)

Buffer(缓冲区)

Selector(选择器/多路复用器)

传统I/O基于字节流或字符流进行操作,而NIO基于新的Channel和Buffer进行操作这是它们的比较

https://img1.sycdn.imooc.com/634eca5a0001748203970207.jpg

至于原理不用记可以这么来理解我始终秉持的态度是如果你在大厂是自研类RPC系统或类MQ中间件的那这个一定要精通否则理解就好不必死磕):

可以看到I/O就像个直肠子直来直去对数据流完全是来者不拒来多少接多少也不管能不能处理得了这样极容易造成线程阻塞也就是电脑卡顿

NIO就有点弯弯绕了它告诉线程如果我忙不过来就别等我你先忙你的所以按照这个约定如果线程发现它不搭理自己的时候就会去忙别的不会造成信息堵车

Channel接口最重要的实现可以分为两大类:用于本地文件和用于网络的Channel

FileChannel:用于本地文件数据的读写

DatagramChannel:用于网络UDP数据的读写

SocketChannel:客户端用于实现网络TCP数据的读写

ServerSocketChannel:服务端用于监听网络TCP的连接请求,每个请求会创建会一个SocketChannel(即客户端连接)

这是和Channel相关的继承结构图

https://img1.sycdn.imooc.com/634eca6e0001446610730680.jpg

I/O本就枯燥如果只是空洞说技术原理就更毫无价值还是上代码NIO和IO比较一下

创建一个普通的Java项目

https://img1.sycdn.imooc.com/634eca790001dffe05870350.jpg

https://img2.sycdn.imooc.com/634eca820001063b05870350.jpg

然后随便在网上或者自己电脑上找一个大文件比如小电影之类的写这样的代码

// 把file1中的内容写到file2中去,看看耗时
// I/O读写
long start = System.currentTimeMillis();
try {
    FileInputStream fis = new FileInputStream("你电脑上已经存在的文件路径,例如C:\\file1");
    FileOutputStream fos = new FileOutputStream("你电脑上还不存在的文件路径,例如C:\\file2");
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fis), 1024);
    String line = null;
    while ((line = bufferedReader.readLine()) != null) {
        fos.write(line.getBytes());
    }
    fis.close();
    fos.close();
} catch (IOException e) {
    e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(end - start);

然后再稍稍改进一下看看byte[]相对于BufferedReader的不同

// 把file1中的内容写到file3中去,看看耗时
// I/O读写(改进)
start = System.currentTimeMillis();
try {
    FileInputStream fis = new FileInputStream("你电脑上已经存在的文件路径,例如C:\\file1");
    FileOutputStream fos = new FileOutputStream("你电脑上还不存在的文件路径,例如C:\\file3");
    byte[] b = new byte[1024];
    int len = 0;
    while ((len = fis.read(b)) != -1) {
        fos.write(b, 0, len);
    }
    fis.close();
    fos.close();
} catch (IOException e) {
    e.printStackTrace();
}
end = System.currentTimeMillis();
System.out.println(end - start);

最后再用NIO试试看

// 把file1中的内容写到file4中去,看看耗时
// NIO读写
start = System.currentTimeMillis();
try {
    FileChannel fis = new FileInputStream("你电脑上已经存在的文件路径,例如C:\\file1").getChannel();
    FileChannel fos = new FileOutputStream("你电脑上还不存在的文件路径,例如C:\\file4").getChannel();
    ByteBuffer bytedata = ByteBuffer.allocate(1024);
    while (fis.read(bytedata) != -1) {
        // 读写交叉进行
        bytedata.flip();
        fos.write(bytedata);
        bytedata.clear();
    }
    fis.close();
    fos.close();
} catch (IOException e) {
    e.printStackTrace();
}
end = System.currentTimeMillis();
System.out.println(end - start);

main()方法中分别执行这三个方法看看耗时上有啥不同尽量找很大的文件比如几个G的那种因为现在计算机的配置都比较高文件太小一会就读完了根本看不出来差别

 

另外,另外,在NIO中如果一个channel是FileChannel类型的,那么可以直接把FileChannel的数据传输到另一个Channel,就像这样

https://img2.sycdn.imooc.com/634ecae30001c0bb05100091.jpg

 

SocketChannel、ServerSocketChannel和DatagramChannel的使用也比较简单,就不堆代码了

Channel提供了一种被称为Scatter/Gather(分散/聚集)的新功能(也称为Vectored I/O,矢量I/O),它在多个Buffer上实现一个简单的I/O操作。说人话就是Scatter是把单个Channel的数据发给多个Buffer分散),Gather则是把多个Buffer的数据发给单个Channel聚集),就像这样

https://img1.sycdn.imooc.com/634ecaed0001065608270343.jpg

同样可以用代码来演示一下

// Scattering reads分散过程
ByteBuffer buffer1 = ByteBuffer.allocate(1024);
ByteBuffer buffer2 = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray1 = { buffer1, buffer2 };
FileChannel channel1 = new FileInputStream("/testfile1").getChannel();
channel1.read(bufferArray1);

// Gathering writes聚集过程
ByteBuffer buffer3 = ByteBuffer.allocate(1024);
ByteBuffer buffer4 = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray2 = { buffer1, buffer2 };
FileChannel channel2 = new FileInputStream("/testfile1").getChannel();
channel2.write(bufferArray2);

 

好了NIO也属于Java中比较重要的内容说多了容易搞晕慢慢来

作者:|湘王爱娟娟|,原文链接: http://www.imooc.com/article/331119

文章推荐

mysql和neo4j集成多数据源和事务

基于Canal实现MySQL 8.0 数据库数据同步

MySQL大量脏数据,如何只保留最新的一条?

golang 必会之 pprof 监控系列(5) —— cpu 占用率 统计原理

Windows 本地安装 Mysql8.0

最新版本 Stable Diffusion 开源 AI 绘画工具之使用篇

逍遥自在学C语言 | 算数运算符

快来玩AI画图!StableDiffusion模型搭建与使用入门~

如何查看当前的 ffmpeg 二进制程序,是否支持 cuda 加速

热点面试题:Vue2、3 生命周期及作用?

且看这个Node全栈框架,实现了个Cli终端引擎,可无限扩充命...

SpringBoot+Mybatis-Plus整合Sharding-JDBC5.1.1实现单库分...