参考: Netty 黑马
目录
阻塞
-
阻塞模式下,相关方法都会导致线程暂停
-
ServerSocketChannel.accept 会在没有连接建立时让线程暂停
-
SocketChannel.read 会在没有数据可读时让线程暂停
-
阻塞的表现其实就是线程暂停了,暂停期间不会占用 cpu,但线程相当于闲置
-
-
单线程下,阻塞方法之间相互影响,几乎不能正常工作,需要多线程支持
-
但多线程下,有新的问题,体现在以下方面
-
32 位 jvm 一个线程 320k,64 位 jvm 一个线程 1024k,如果连接数过多,必然导致 OOM,并且线程太多,反而会因为频繁上下文切换导致性能降低
-
可以采用线程池技术来减少线程数和线程上下文切换,但治标不治本,如果有很多连接建立,但长时间 inactive,会阻塞线程池中所有线程,因此不适合长连接,只适合短连接
-
所以阻塞模式的IO比较适合短连接,一次连接很快就可以完成读写,立马关闭,进行下一个连接和读写。
非阻塞
-
非阻塞模式下,相关方法都会不会让线程暂停
-
在 ServerSocketChannel.accept 在没有连接建立时,会返回 null,继续运行
-
SocketChannel.read 在没有数据可读时,会返回 0,但线程不必阻塞,可以去执行其它 SocketChannel 的 read 或是去执行 ServerSocketChannel.accept
-
写数据时,线程只是等待数据写入 Channel 即可,无需等 Channel 通过网络把数据发送出去
-
-
但非阻塞模式下,即使没有连接建立,和可读数据,线程仍然在不断运行,白白浪费了 cpu
-
数据复制过程中,线程实际还是阻塞的(AIO 改进的地方)
多路复用
单线程可以配合 Selector 完成对多个 Channel 可读写事件的监控,这称之为多路复用
-
多路复用仅针对网络 IO、普通文件 IO 没法利用多路复用
-
如果不用 Selector 的非阻塞模式,线程大部分时间都在做无用功,而 Selector 能够保证
-
有可连接事件时才去连接
-
有可读事件才去读取
-
有可写事件才去写入
-
限于网络传输能力,Channel 未必时时可写,一旦 Channel 可写,会触发 Selector 的可写事件
-
-
-
channel 必须工作在非阻塞模式
-
FileChannel 没有非阻塞模式,因此不能配合 selector 一起使用
-
绑定的事件类型可以有
-
connect – 客户端连接成功时触发
-
accept – 服务器端成功接受连接时触发
-
read – 数据可读入时触发,有因为接收能力弱,数据暂不能读入的情况
-
write – 数据可写出时触发,有因为发送能力弱,数据暂不能写出的情况
-
调用 selector 的 select() 会阻塞直到 channel 发生了读写就绪事件,这些事件发生,select 方法就会返回这些事件交给 thread 来处理
进阶版:主从多线程
就是 netty 提供的 BossGroup线程池只负责 连接
WorkerGroup线程池只负责读写
解决的问题:
短时间大量请求打过来建立连接,建立连接完毕后进行读写操作,这样selector就会阻塞的进行读写,不能及时的处理其他请求的连接或者读写事件。
使用主从多线程,一个线程池BossGroup只处理连接,建立连接后由另一个线程池WorkerGroup进行读写事件,此时BossGroup可以处理其他的连接事件。
进阶版:主从多线程+业务线程池
上述netty的主从多线程模型,在应对如下任务时并发量会下降:
请求是需要在本地经过一个比较耗时的操作后才会返回结果给channel。
这样如果WorkerGroup线程池就没有可用的连接,此时可以再添加一个线程池,专门处理这种耗时的操作。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92833.html