Netty 死锁异常
序
最近,我发现一些BlockOperationException异常出现在我的Netty4项目中,为什么会出现这个异常?有人说,在Netty的ServerBootstrap启动服务器的时候,使用sync()或await()方法会造成死锁,可我发现异常是出现在ChannelRead过程中,而且Bootstrap用的是bossGroup,而ChannelRead用的是workerGroup,两者使用的EventLoop应该是不用的,我认为是不会互相影响的,那究竟是什么原因产生思索异常呢?
我将这个问题发布到了StackOverflow进行提问(https://stackoverflow.com/questions/46020266/what-causes-blockingoperationexception-in-netty-4),非常幸运的得到了Norman Maurer(Netty的核心贡献者之一)的解答。

下面我将整个问题的分析思路整理出来,与大家分享。
正文
在使用Netty的ServerBootstrap启动服务器的时候,使用sync()方法会导致阻塞。
public void init() throws Exception {
logger.info("start tcp server ...");
Class clazz = NioServerSocketChannel.class;
// Server 服务启动
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boosGroup, workerGroup);
bootstrap.channel(clazz);
bootstrap.childHandler(new ServerChannelInitializer(serverConfig));
// 可选参数
bootstrap.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024);
// 绑定接口,同步等待成功
logger.info("start tcp server at port[" + port + "].");
ChannelFuture future = bootstrap.bind(port).sync();
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
logger.info("Server have success bind to " + port);
} else {
logger.error("Server fail bind to " + port);
throw new InitErrorException("Server start fail !", future.cause());
}
}
});
}
在这一行
ChannelFuture future = bootstrap.bind(port).sync();
bootstrap.bind()返回一个ChannelFuture,查看源代码DefaultChannelGroupFuture,sync()方法会调用await(),在await()中对ChannelFuture对象进行了加锁。
public Promise<V> sync() throws InterruptedException {
await();
rethrowIfFailed(); // 异步操作失败抛出异常
return this;
}
sync()和await()很类似。
public Promise<V> await() throws InterruptedException {
// 异步操作已经完成,直接返回
if (isDone()) {
return this;
}
if (Thread.interrupted()) {
throw new InterruptedException(toString());
}
// 同步使修改waiters的线程只有一个
synchronized (this) {
// 未完成则一直循环
while (!isDone()) { // 等待直到异步操作完成
// 死锁检测
checkDeadLock();
incWaiters(); // ++waiters;
try {
wait(); // JDK方法
} finally {
decWaiters(); // --waiters
}
}
}
return this;
}
注意其中的checkDeadLock()方法用来进行死锁检测:
This chapter requires login to view full content. You are viewing a preview.
Login to View Full Content