[转]Netty进阶之路ChannelHandler并发安全、NioEventLoop防阻塞挂死

编程

  《Netty进阶之路》第7章、第8章分别提出ChannelHandler并发安全问题,NioEventLoop线程阻塞导致消息接收和处理缓慢。ChannelHandler的并发安全问题很好分析,NioEventLoop线程阻塞则需要一些技巧。
  

1 ChannelHandler并发安全
  默认每个Channel中有各自的ChannelHandler实例,因此如果所有业务在NioEventLoop中完成则没有线程安全问题,因为从消息接收到响应写出阶段都由同一个NioEventLoop线程处理;若在ChannelHandler消息处理过程中新开启一个线程,则新线程和NioEventLoop同时读写ChannelHandler中的变量时会有线程不安全的风险。

@Component(value = "gatewayChannelInitializer")

public class GatewayChannelInitializer extends ChannelInitializer {

    private static final String ENCODER = "encoder";

    private static final String DECODER = "decoder";

    @Autowired

    private BusyMan busyMan;

    protected void initChannel(Channel channel) throws Exception {

        // 每个Channel一个GatewayChannelHandler实例

        GatewayChannelHandler gatewayChannelHandler = new GatewayChannelHandler();

        gatewayChannelHandler.setBusyMan(busyMan);

        ChannelPipeline pipeline = channel.pipeline();

        pipeline.addLast(ENCODER, new HttpResponseEncoder());

        pipeline.addLast(DECODER, new HttpRequestDecoder());

        pipeline.addLast(gatewayChannelHandler);

    }

}


  如果ChannelHandler像下面这样用@Sharable标注LauncherChannelHandler 为共享实例,则多个NioEventLoop共用一个LauncherChannelHandler实例,它们并发访问ChannelHandler,此时ChannelHandler的变量被并发读写,存在线程不安全的风险。

import io.netty.channel.ChannelHandler.Sharable;

@Sharable

public class LauncherChannelHandler extends ChannelInboundHandlerAdapter {

}


2 NioEventLoop高性能
  8.2.4的总结是,要防止NioEventLoop阻塞挂死,最佳实践是:

①两个以上NioEventLoop线程构成Reactor模式(Netty服务端模式会自动构建Reactor模式);

②尽量不要在NioEventLoop线程中新开线程;

③解码不要新开线程;

④业务如果耗时很短,不要新开线程;

⑤耗时操作不要放在NioEventLoop执行,必须新开线程执行,最好利用线程池和生产者消费者模式。


  第①⑤点很好理解,第②③④在说同一个事情:如果耗时很短,不要自己开启新线程异步处理,因为新开启线程的目的是利用多核优势节省时间,而耗时很短的运算新开线程收益不大。那就是说,是否开启新的线程取决于“异步带来的时间收益”和“多线程切换开销”之间的权衡。
  NioEventLoop从SingleThreadEventLoop继承了一个任务队列Queue tailTasks,SingleThreadEventLoop从SingleThreadEventExecutor继承了一个任务队列Queue taskQueue和线程池Executor executor,在这个线程池中首先启动模板方法run()(实现方法在NioEventLoop中:一个for循环处理所有socket事件),SingleThreadEventExecutor从AbstractScheduledEventExecutor继承了一个带优先级的定时任务队列PriorityQueue<ScheduledFutureTask<?>> scheduledTaskQueue。因此,在NioEventLoop中最好不要自己新开线程执行异步任务和定时任务,NioEventLoop已经具备这些基础设置。
————————————————
版权声明:本文为CSDN博主「旧城灯火」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_32717909/article/details/93530639

以上是 [转]Netty进阶之路ChannelHandler并发安全、NioEventLoop防阻塞挂死 的全部内容, 来源链接: utcz.com/z/511473.html

回到顶部