Java NIO的核心组件简介和使用

图片来自nidan-455298会员

在Java Socket通信中,Java NIO是一个很重要的底层实现类,理解其核心组件和使用方法,将会帮助了解更多在Java NIO基础之上搭建的其它Socket通信应用,例如Netty IO等。

本文将对Java NIO 核心组件做一个简单介绍,读完本文,你将可以读Java NIO有个总体上的认识,并能够通过代码样例,编程实现一个多线程异步消息通信。

1. Java NIO概览

Java NIO全称是Java New Input/Output,是很早在JDK1.4中引入的输入输出类库,之后在JDK7中提供了升级版的NIO2,提供了异步编程模型的IO操作。下文若没有说明,Java NIO是指在JDK7之后的最新NIO类库。

有一个首先需要了解的问题是,为什么会有NIO?和之前的IO类库相比,其带来了哪些优点和改进?

在JDK1.4之前,所有IO操作都是基于流(stream)进行数据读写,其读写操作方法会阻塞,这将大大影响程序的效率。Java NIO一方面解决了阻塞的问题,另一方面对数据块存储、数据处理方面进行了抽象,提供了缓存区、通信通道和选择器三个组件概念,使得程序开发者可以在更深入的层次上介入IO处理过程,对相关的通信进行多线程优化,编程可扩展性大大提高。

下表列出IO和NIO在主要特性上的区别对比,

IO NIO
操作对象 面向流 面向缓存区
操作特性 单向操作,或读,或写 支持读写双向操作
读写单位 按字节一一进行读/写 Bytes 按指定块存储大小进行读/写 Block Buffer
支持非阻塞 只支持阻塞读写 支持阻塞和非阻塞读写
通信通道 无,一个流本身就是一个通道 基于通道进行数据传输
单线程 多通道 不支持 支持,通过选择器实现一个线程处理多个通道
异步编程 不支持 支持异步编程模型(自JDK7)

可以看到Java NIO在IO操作上进行了很大幅度的改进和提升。

在Java NIO类库中,有四个核心组件接口,

  1. Channel通道
  2. Buffer缓存区
  3. Selector 选择器
  4. CompletionHandler 异步回调处理器

本文将对这四个组件逐一进行讲解,了解其作用和使用方法,并提供简单的代码使用样例。最后给出一个多线程异步通信的使用样例。

2. 通道Channel

一个通道是数据传输的连接,可以和IO设备建立连接,进行数据的获取和传送。在一定程度上,可以认为通道是流的升级版实现。

整个Java NIO中最常用的通道类有如下几个,

  • FileChannel,since 1.4
  • DatagramChannel,since 1.4
  • SocketChannel,since 1.4
  • ServerSocketChannel,since 1.4
  • AsynchronousFileChannel,since 1.7
  • AsynchronousSocketChannel,since 1.7
  • AsynchronousServerSocketChannel,since 1.7

其中Asynchronous*这几个类是在JDK7开始提供的NIO 2.0类库,主要提供了异步编程模型,详细见后面异步回调处理器的讨论。

(注:AsynchronousDatagramChannel在JDK7中并没有提供,原先是有准备发布这个类库的,但是由于某些原因,在发布前被删除。)

通道类中使用最多的四个方法是,

  • Channel.bind() 绑定连接
  • Channel.accept() 建立连接
  • Channel.read(buffer) 把数据从缓冲区读到通道
  • Channel.write(buffer) 把数据从通道写到缓冲区

一个简单的代码样例如下,

// please note: configure channel blocking state as false
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);

System.out.println("A server is started on port 9000");
ServerSocket serverSocket = server.socket();
serverSocket.bind(new InetSocketAddress(9000));

// please note: server.accept() will not block current thread
// Accept method will return null directly if no client is connected
SocketChannel channel = null;
int count = 0;
while (channel == null) {
    System.out.println("The server is trying to connect client, count=" + count++);
    channel = server.accept();
    Thread.sleep(500);
}
//channel.read(ByteBuffer)

System.out.println("the end");
channel.close();
server.close();

3. 缓冲区Buffer

Java NIO是基于块进行IO操作,缓冲区就是对这个块的抽象定义,在这个缓冲区中可以反复进行读写,通过通道实现数据的传输。

我们先看看缓冲区是什么样子,一个缓冲区是一个有指定大小的数组,其有读模式和写模式两种状态,请注意在读写不同模式下其Position和Limit的位置指向, 上图的缓冲区中显示了如下三个属性,

  • Capacity:缓冲区容量大小
  • Position:缓冲区的读写位置,根据当前读/写模式,含义如下
    • 在读模式下,读的当前位置
    • 在写模式下,写的当前位置
  • Limit:缓冲区的读写限制位,根据当前读/写模式,含义如下
    • 在读模式下,可以读的最大位置,等于当前缓冲区内数据量,防止读溢出
    • 在写模式下,可以写的最大位置,其实就等于Capacity值,防止写溢出

读李笑来的《财富自由之路》

李笑来 著

昨天拿起李笑来的《财富自由之路》一书,一口气读完,对里面讲的一些内容深有体会。人生其实很短暂,三年一个时代,十二年一个轮回,每个人都有机会在自己的财富自由之路上走地更远,问题是你愿不愿意?

财富

什么是财富?钱、黄金、房子,或者其它。我们的财富难道就这些么?我们的自由、我们的时间、我们的思考、我们的家人,难道不是我们的财富么?我们的财富确实很多,但我们花了多少时间去了解这些财富,怎样才能让我们的财富富有起来,我们又是怎样花销掉这些财富的。当我们慢慢去思考这些问题的时候,我们会发现,原来我们是这样愚钝、奢侈和浪费。

有几个财富,是有理由让我们需要知道的,

  • 时间
  • 注意力
  • 思考

时间

上帝在创造人的时候,给了每个人最公平的事情是,我们每个人的每天时间都是一样的,24小时,不多一分,也不多一秒。如果我们每个人都是用时间来创造价值的话,我们都在做一种交换,以时间交换我们想要的东西,这是一种交易。

世界上的人,按对时间的交换方式,大概可以划分如下三类商业模式进行赚钱,

  1. 卖自己的一份时间
  2. 把自己的一份时间卖出多份
  3. 买别人的时间,成为自己的时间

第一种是方式应该很熟悉,我们上班工作时,把自己一天8小时的时间卖给公司,赚取薪水。一天24小时,勤奋点,可以卖个18小时,然后睡6小时,这已经是极限。这种方式是积累财富最简单的方式,它不可耻,劳动光荣,而且这是我们成长的必经之路。这是大多数人出售自己时间的方式,但很大的问题是,在劳动的同时,你是否有成长。

第二种方式比第一种高级一些,我们一天确实只有24小时,但我们有没有办法把它卖出多份?这种方式确实有,写书就是一种,各种知识产权的也是,软件开发也是,工厂的模具设计也是,当花个1个小时写一篇文章,花一天设计开发一个软件,虽然刚开始要花些时间,但接下来可以批量复制、批量执行,不断卖出多份。这种方式易懂,但不易学,将时间卖出多份还需要一定的智慧。

第三种方式属于做老板们,购买别人的时间,为自己做事。不是每个人都适合成为老板。

时间是宝贵的,一份耕耘,一份收获,你愿意将时间投入到哪里,哪里就会有你的产出。

注意力

李笑来在书中谈到,什么是我们每个人的最宝贵财富?

很多人觉得是时间,但是仔细思考,会发现时间不受我们控制,我们无法创造它,也无法抛弃,你不用它,它就从你身边流过。还是一句话,上帝是公平的,一天24小时,每个人不会多一分,也不会少一秒。

那什么是我们能拥有的最宝贵财富?答案:注意力。李笑来在书中对其的定义,

  • 注意力是你唯一可以随意调用且能有所产出的资源

若你将注意力放在学习上,你有所进步;若将注意力放在思考上,你将提升你的认知;若你将注意力放在没有任何产出的地方,那你就惨了,你将没有任何成长。

非常可惜的是,我们都在挥霍我们的注意力,莫名其妙凑热闹,心急火燎随大流,为别人操碎了心,刷微信朋友圈,追娱乐明星新闻,看连播电视剧。我们的注意力就这样被消费了,被别人消费了!没有一件事会带来你财富的成长,或者说,你的成长。

把注意力、时间、金钱的重要性进行比较,从高到低,

注意力》时间》金钱

你的注意力比时间更重要,你的时间比金钱更重要。这样相比之下,你会发现,你的金钱是最便宜的。

思考

在人类的进化史上,猿人和动物的区别,在于猿人会制造和使用工具,人和猿人的区别在于,人会使用文字和语言。现在的人作为高级动物,都有思考的能力,但是否愿意思考,却不是每个人能做的到、做的好。

思考是一个人自我进化的关键方式,若将我们自己的脑袋思维比喻为一个操作系统,那么思考就是这个操作系统更新升级的方式。

人一生中,会不断形成自己的思维,这个思维因人而异。最开始的是上学的时候获取对这个世界的认识,毕业后则根据社会历练,不断的变化着自己的思维。在这个过程中,你有没有过认真地对某个问题进行详细深入的思考?甚至一遍又一遍的思考。有些人的思考是被动的,碰到问题才思考,好听点叫逢山开路、遇水搭桥,难听点叫随波逐流、穷则思变。思考本身是一个主动的行为,但大多数的时候,和对注意力一样,我们也放弃了自己的主观能动性。

学会思考,不断地为我们的思维更新换代。

成长

一夜暴富的新闻故事,每天拨动着人们的心弦,每个人在想,要是那个暴富的人是我会怎样?于是彩票、赌博屡禁不止。

实际上的一个人的成长是怎样的?请看一个指数曲线,

上面的指数曲线说明这样的问题,一个人的成长,在很长的时间内,看不出太大的变化,但是一旦到了拐点后,其成长将会迅速升高,未来变得无限可能。

想要有这个的成长曲线,问题是,你每天有成长么?

书籍:财富自由之路 作者:李笑来,ISBN 9787121320088 评分:4分,推荐阅读,评分详细说明见这里。