一:Java IO 模型
兄弟们,什么是Java的IO呢?首先我们看看这两个单词的全拼,不就是Input 和Output嘛?那么到底是什么的输入和输出呢?本质上在互联网的世界中,不就是数据的输入输出吗?而我们java 中对于数据的这个输入和输出都是基于线程来说的,那么线程在接收这个数据的输入和输出的时候线程的状态是怎么样的呢,在一直等待还是说先干自己的事,等数据来了再去接收这个数据呢?所以这个就涉及到了我们的这个IO模型了。它分为下面几种
1.1: 阻塞IO模型
这听上去像是线程被阻塞了,对头,不用怀疑自己,兄弟,就是线程在等待数据的时候,啥事都不干,把CPU也全部交出去了,自己像个舔狗一样迟迟地等待数据女神的到来,这个时候线程是不做任何事的,所以相当于别人把它定格了,静止在那里了,阻碍它做事了,所以这个叫阻塞IO模型
1.2: 非阻塞IO模型
和上面的老弟相比,好像这个听上去不那么傻帽了,是的,这个线程哥们在要读数据或者写数据的时候不会想舔狗一样把自己的所有东西,就是最核心的CPU资源交给别人,它会怎么做呢?它知道数据女神会经过那里,然后它就去那里蹲守,不停地张望,隔一分钟看一次,看看女神来没来,因为没有东西把它定住,它还是会活动的,所以叫非阻塞IO模型
1.3:多路复用IO模型
多路复用IO模型咋一听很高大上,难不成是把刚刚的阻塞IO模型和非阻塞IO模型融合到一起来吗?哈哈哈,然后立马估计就会有兄弟们笑着说,融合到了一起估计也还是舔狗,没有多大作用。对头,所以咱们就来个改进版的,既然舔狗当地那么没有尊严,那么我们就招聘一个小啰啰去守候女神了,咱该干啥就干啥,是不是。所以现在目前的情况就是这样的,假设现在有5个线程需要读取或者写入数据,那么就由这五个线程凑钱去招募一个小啰啰线程,他会不停的去看看这五个线程对应的通道有没有数据过来,有了它就会通知对应的线程兄弟准备好启动IO动作去和这个数据交互了,这个通道就是我们之前说的socket,一个小啰啰线程管理多个socket,实行监察百官之责哈哈哈。
但是兄弟们有没有发现,如果某个通道的数据量太大,而那个小啰啰线程一直在照看这个通道的数据处理,其他线程即使进来了他也不知道,来不及通知,这个也会造成其他线程的数据缺位对吧。这算是一个小缺点吧。之前我们虽然叫那个小啰啰线程,但是它的地位可不低呢,是重金请来的,是操作系统的一个内核线程的哥们,处理起来事件响应嘎嘎快,所以效率很高的呢!
1.4: 信号驱动IO模型
兄弟们可能又会有疑惑了,刚刚要进行IO操作的时候不是都接到了数据来的信号吗,这个信号IO模型算个什么鬼?哈哈哈,别急别急,大家。此信号非彼信号,这个信号是需要IO操作的线程哥们向操作系统注册的一个信号,比如一个线程叫做9线程,然后它向操作系统注册一个信号为9线程–signal-Input-position-88 , 这就表明9线程想在88号为读取数据;等到数据来了的时候操作系统会通知9线程,“哎,兄弟,88号位来数据了,准备开始干活了”,然后9线程就屁颠屁颠地开启read 操作读取数据了。
1.5: 异步IO模型
一听这个异步IO模型是不是有点来气,刚刚所谓的多路复用IO模型和信号模型也是异步的啊,也没有说就苦苦地在那里等待数据的到来啊,自己该干嘛也干嘛了啊。各位客官稍安勿躁,这个异步IO模型不是说等待数据的异步,而是处理数据也他么的异步,我就问你牛逼不牛逼,就是说即使数据到了我他么地也是干自己的活,数据读取操作我他么地全部交给操作系统的内核给我去完成,这才叫挟天子以令诸侯;当我要读取数据的时候我就告诉内核一声,然后接下去的工作我就全部交给操作系统的内核线程去帮我完成了,等数据读取完成它告诉我一声就可以了。真是把异步演绎到了极致,这是所有的IO线程的楷模啊!
所以这个模型就是两步,一个是发送信号给内核线程,内核线程在等待数据到来以及搬运数据到用户线程,搬运完成通知用户线程一声;它和信号模型不同的就是信号模型需要自己处理数据,而它把所有的工作交给内核线程去完成了。
二:Java NIO
刚刚讲完了IO,这又来了一个NIO,兄弟们可能会疑惑,NIO他娘的就是Not IO 或者 Not only IO吗?哈哈哈哈,这个想法不错,联系上了大数据的NoSql; 但是并不是,兄弟们,NIO的全称是Not Blocking IO,翻译过来就是非阻塞IO,这好家伙,命名能规范一定吗,你叫个NBIO兄弟们但凡联想多一点也就可以猜测出来了,不扯了,咱接下来进入正题。
结合上面我们讲的那些个IO模型,兄弟们可能明白了这个NIO不就是多路复用模型,信号驱动模型或者异步IO模型里面的一种吗?毕竟他们作为非阻塞IO模型还有点看头,是的,不打谜语了,兄弟们,这个NIO用的模型基本上就是这个多路复用模型,话不多说,我们先上图看看这个Java NIO 的实际网络模型是咋样的。
兄弟们可以对比下,这个Java 的NIO 模型比那个多路复用模型多了一个所谓的Buffer, 就是个缓冲区的作用,那个Thread 就是那个小啰啰线程,Channel 就是那个所谓的通道,Selector 就是小啰啰线程的具体执行人,时刻监控这这个Channel 里面的事件。所以这个具体工作流程就是如下所示:
1: 在一个进程里面有6个线程,以后会进行IO操作,这六个线程就主动想进程汇报,申请需要个小啰啰线程来帮忙监听下数据的到来
2: 然后进程就想老大操作系统申请了一个这样工作的线程,老大操作系统说对于数据输入输出这么重要的任务,必须给精兵强将去执行,然后派遣了内核线程,相当于御林军,监控效率极高。
3: 当内核线程到达了指定位置之后,就首先排除一个selector 小弟去监控这些线程上交上来的通道名单中有没有对应的数据进来,有了就和上级汇报,上级再把这个情况传递给对应的线程处理
4: 对应的线程收到消息后就Channel 通道中把相应的数据拉到Buffer池中来,然后等待一波直至Buffer 池中快满了才进行后续的处理,这样就不至于频繁地去处理这个数据,浪费资源。
不过这里有几个点兄弟们要注意下,相对于普通的IO操作,此时线程在处理Buffer 数据的时候会更灵活,毕竟都在自己的池子里了,想怎么操作怎么操作不是吗,可以不按顺序访问,相对于IO的来一个数据处理一个数据不一样。而且这个Buffer 池子就是一个数组,说白了,它的子孙有以下几个: