为什么初学者觉得 JAVA 的 IO 很复杂?
确实是,我在十多年前刚接触java IO的时候,觉得真复杂,而且里面的类也多,一会又是字节了一会又是字符了,一会又是gbk一会又是iso-8859-1了,一会又是Writer了一会又是OutputStream了,一会又是打印流了,一会又是readLine了,一会又是管道模型了,反正是非常复杂。
同步IO已经够我喝一壶了,后面又学习了AIO、NIO,那个学起来更懵,感觉很多东西的处理真的是过渡设计了,我就是要输出一个数据,为什么还要搞这些?
不仅仅是初学的时候不擅长,其实我工作了三四年了都还不是特别清楚这些东西。
直到有一次,我们项目当中用到了Vertx,目的是为了解决海量并发连接数的问题,我才慢慢开始体会到NIO的一些作用。
所以,什么是Vertx,为什么会因此我就慢慢懂NIO了?
我们做的是一个物联网的项目,同时在线的设备达到百万级别,同时在线嘛,那肯定就是要tcp长链接了,要不然怎么叫在线呢?所以对于机器而言,就是要支持越多的tcp链接就越好,机器的瓶颈就在tcp连接数这里。
而一台机器的性能,当时的业务及其处理能力,可以支持的tcp连接数大约在5千左右(理论上远不止这么多),如果使用传统的BIO模型,就会需要5千多条线程阻塞在那里等待,所以会导致单台机器的线程数爆炸问题。
那么怎么办呢?总不可能把每台机器的连接数降下来吧,但是连接数太多就意味着线程数也会增多,而一台机器的线程数达到了2千就非常多了,会导致大量的线程上下文切换以及线程调度会消耗额外的CPU,cpu尽在维护这些线程了,加大硬件其实也不行,因为操作系统的性能也有瓶颈的(在购买云机器的时候会有比较多的体会)。
有没有一个办法,少数线程就可以满足大量的tcp连接呢?实际上是有的。
这就是Linux的五种经典网络编程模型,如果不太熟悉的可以看看Linux网络编程相关的技术,其中有一种变编程模型就是同步非阻塞式的,NIO用的就是这种方式。
其实就是使用更少的线程,来处理更多的tcp请求,这种方式就叫做多路复用技术。
Vertx用完之后的情况
当我们使用完了这个技术之后,线程数量只需要4个线程就行了,能够处理四五千的连接毫无压力,上下文切换的次数也从好几万下降到了四千多的样子,cpu的sys消耗也明显下降了20%多。从那次以后,我就知道了这个NIO是真正的高并发,不懂NIO就真不算什么高并发工程师的。我也是从那个时候开始,对高并发才有了一个比较清楚的概念,高并发是必须要网络达到高并发才能算是高并发的,不是说你的程序快就算是高并发了。
所以说,这一块的东西,需要你在实际项目中有体会,你才会觉得这个东西真的很好,有经历有见识,能够在实践中看,才会觉得这个技术好。
所以,大部分初学者学起来是相当困难的,这也是正常现象,毕竟理工科这种东西,主要在于实践,没有亲身经历过,没有见过,硬学是相当痛苦的。
不过,如果你是初学者,我可以建议你先看看Linux网络编程,学习一些基本的网络编程模型,知道同步阻塞、同步非阻塞、异步非阻塞等编程模式之后,再来学习NIO就会很轻松了,毕竟NIO的底层原理就是同步非阻塞的编程模型,用的是多路复用技术。
同时你也可以写一些Linux网络编程的小例子,然后对比一下这几种网络模型的优劣势,你可以使用jmeter这样的工具进行大并发测试一下。
这样你还可以学习一些Linux性能诊断的知识,对以后也是有帮助的,还可以学习压测方面的知识,然后NIO的底层也理解了,同时还会C语言了,以后如果懂Linux网络编程,将会是你的优势。
当然,至于原来的那些BIO的东西,底层原理就是Linux的同步阻塞网络模型,你只要会那个底层的技术就行了,BIO里面有很多花哨的输入输出Stream其实不用太在意,我工作了将近二十年了,也没有说对这一块专门的去研究过,实际上用的并不是很多,会读取文件、会输出到文件,会输出到控制台就行了,其他的可以不用过分研究。
当然,里面有些东西需要用到编码的知识,如果对编码的本质以及代码的编码、编译的编码、文件读取的编码、内存数据的编码等关系理不清楚的话,是很容易出现乱码的,解决乱码的能力也很考验一个程序员的基本功的!