NIO 多线程版Reactor 阻塞问题 源码解析

158 阅读1分钟

需要对NIO底层源码有一定了解

概要: 在写Reactor模式多线程版版 出现了boos selector(就是处理channel连接的selector)往 worker selector 注册channel出现了阻塞问题(卡死不动了)。

image.png 问题就出现在断点处

MultiThreadEchoHandler 类会在boos selector接受到连接事件并接受之后初始化 然后把this 注册到worker selector中

image.png

boos selector接受到连接事件 往 worker selector中注册!!

image.png

源码解析:

seletor,channel,seletionKey 关系图

image.png

Channel.Rgister源码方法:

image.png

如关系图和源码所示 selector与channel 通过selectionKey双向绑定的!

Selector.Rgister源码方法:

image.png

如图所示 seletionKey以impl实例化封装channel与selector

在真正做注册动作之前需要获得keys set集合的对象锁

阻塞就产生在这里 一直被阻塞住 锁一直没被释放!!

那么我们的问题就出来了!!谁在boss selector 给worker selector注册channel时一直占这个锁

这里用jconsole 看看锁占用情况.

image.png

线程锁占用情况就可以看出 boss selector 往 worker selector注册时 锁一直就被worker自身占用着!

那么第二个问题就时worker什么方法会阻塞占锁

答案就是 select 调用的操作的系统的epoll

image.png

**select 会阻塞占锁 ,所以boss selector 往这个正在阻塞的selector 注册 会把boss selecor一直阻塞(-.- 有点绕) **

解决方案: 只要 boss selector 来注册了 就立即通知 worker selector立即放弃锁

image.png