java 同步非阻塞的nio中包含阻塞的selector的理解

java 同步非阻塞的nio中包含阻塞的selector的理解

 

nio与selector的联系:

NIO自从JDK1.4版本以来就添加的一个非阻塞I/O框架,NIO是Java为解决网络通讯中高并发问题的一个类库,Selector是java NIO的一个组件,用于检查一个或多个NIO Channel的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接,所以Selecotr是实现了多路复用的关键。

纠结点:

java nio是非阻塞的,但是java的selector组件确实阻塞的(当线程进入阻塞状态,是不占用CPU资源的。多么nice的设计理念),那为什么还要称java nio是非阻塞的呢?

解释:

java nio说的非阻塞指的是对于io操作来说是非阻塞的,传统bio在进行socket.accept()、socket.read()、socket.write()三个主要函数时都是同步阻塞的,多说一点因为是同步阻塞所以如果是单线程、且io一直没有数据那么系统将会被一直挂在那里。
而nio一般会有很多io操作,当有任何一个io有数据 ,selector就被唤醒,所以在这条线程中,当io1没有数据处于等待时,io2可能正在被处理,所以这条线程并没有被这个io1阻塞。
所以说java nio说的同步非阻塞指的是对于io操作来说,而并非对于整个java nio 来说都是非阻塞的
因为java nio 的selector是阻塞的,虽然说selector是阻塞的但是它实现了多路复用,而且相对于传统io,nio还节省了线程,以及线程之间切换带来的系统消耗。
所以通过分析,同步非阻塞的nio中包含阻塞的selector,只是关注的点不同而已,而且严格意义上将java nio应该说是多路复用,而不是同步非阻塞。

 

扩展

为什么说线程是很贵的资源?

线程的创建和销毁成本很高,在Linux这样的操作系统中,线程本质上就是一个进程。创建和销毁都是重量级的系统函数。
线程本身占用较大内存,像Java的线程栈,一般至少分配512K~1M的空间,如果系统中的线程数过千,恐怕整个JVM的内存都会被吃掉一半。
线程的切换成本是很高的。操作系统发生线程切换的时候,需要保留线程的上下文,然后执行系统调用。如果线程数过高,可能执行线程切换的时间甚至会大于线程执行的时间,这时候带来的表现往往是系统load偏高、CPU sy使用率特别高(超过20%以上),导致系统几乎陷入不可用的状态。
容易造成锯齿状的系统负载。因为系统负载是用活动线程数或CPU核心数,一旦线程数量高但外部网络环境不是很稳定,就很容易造成大量请求的结果同时返回,激活大量阻塞线程从而使系统负载压力过大。

传统bio的缺陷

传统bio依赖于多线程,多线程一般都使用线程池,可以让线程的创建和回收成本相对较低。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的I/O并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是当面对十万甚至百万级连接的时候,传统的BIO模型是无能为力的。

posted @ 2022-10-10 14:45  r1-12king  阅读(160)  评论(0编辑  收藏  举报