ChannelHandler是Netty中使用最广的接口,Netty提供了大量内置的ChannelHandler实现类,包括编解码、SSL、日志打印等等。用户通过实现ChannelHandler接口,来接口和发送业务消息,并进行业务逻辑处理。
Netty ChannelHandler并发安全问题
串行执行的ChannelHandler
跨链路共享的ChannelHandler
ChannelHandler并发场景总结
Netty ChannelHandler并发安全问题
业务有一个非线程安全的类ThreadUnsafeClass,这个类会在业务ChannelHandler的channelRead方法中被调用。下面这样的调用方法在多线程环境是否安全:
public class ServiceHandler extends ChannelInboundHandlerAdapter{
private ThreadUnsafeClass unsafe = new ThreadUnsafeClass(); //非线程安全类
public void channelRead(ChannelHandlerContext ctx, Object msg){
//此处调用是否正确?
unsafe.doSomething(ctx, msg);
}
}
串行执行的ChannelHandler
如果ChannelHandler是非共享的,则它就是线程安全的,原因:当链路完成初始化会创建ChannelPipeline,每个channel对应一个ChannelPipeline实例,业务的ChannelHandler会被实例化并加入ChannelPipeline中执行,由于某个Channel只能被特定的NioEventLoop线程执行,因此ChannelHandler不会被并发调用,不用考虑线程安全问题,相关源码:
.handler(new ChannelInitializer<SocketChannel>(){
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new NoThreadSecurityClientHandler()
);
}
});
业务可能会多线程调用ChannelHandlerContext或者Channel的write方法,这会不会导致多个业务线程并发调用ChannelHandler呢?答案是并不会产生并发安全问题。在执行write操作时,会判断是否是下一个要执行wirte操作的AbstractChannelHandlerContext的EventExecutor线程,如果不是则将write操作封装成AbstractWriteTask放入线程任务队列异步执行,原调用线程返回。如果业务的ChannelHandler没有指定EventExecutor,则使用的就是消息读写对应的NioEventLoop线程。因此即便多个业务线程并发调用某个Channel,也不会产生多个线程并发访问业务ChannelHandler的问题。源码如下(AbstractChannelHandlerContext类):
private void write(Object msg, boolean flush, ChannelPromise promise){
AbstractChannelHandlerContext next = findContextOutbound

本文探讨Netty中ChannelHandler的并发安全问题,包括串行执行的ChannelHandler、跨链路共享的ChannelHandler及并发场景总结,强调了线程安全的重要性。
1765

被折叠的 条评论
为什么被折叠?



