Java ShutdownGracefully()永远不会返回

Java ShutdownGracefully()永远不会返回,java,netty,Java,Netty,在这段代码中,shutdownGracefully().syncunterruptibly()永远不会返回。 这是预期的行为还是我误解了什么? 使用netty 4.0.35.Final进行测试 public class ShutdownGracefullyDemo { private ServerBootstrap bootstrap; public static void main(String[] args) throws Exception { new S

在这段代码中,shutdownGracefully().syncunterruptibly()永远不会返回。 这是预期的行为还是我误解了什么? 使用netty 4.0.35.Final进行测试

public class ShutdownGracefullyDemo {
    private ServerBootstrap bootstrap;

    public static void main(String[] args) throws Exception {
        new ShutdownGracefullyDemo().initialize();
    }

    private void initialize() throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        bootstrap = new ServerBootstrap();
        bootstrap.group(group)
            .channel(NioServerSocketChannel.class)
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new MyInboundHandler())
            .bind(2025)
            .sync()
            .channel()
            .closeFuture()
            .sync();
    }

    @ChannelHandler.Sharable
    private class MyInboundHandler extends SimpleChannelInboundHandler<ByteBuf> {
        Charset charset = Charset.forName("US-ASCII");

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg)
            throws Exception {
            String data = msg.toString(charset);
            System.out.println("Received: " + data);
            if ("quit\r\n".equals(data)) {
                shutdown();
            }
        }
    }

    private void shutdown() {
        if (bootstrap != null && bootstrap.group() != null) {
            bootstrap.group().shutdownGracefully().syncUninterruptibly();
            System.out.println("shutdown completed");
        }
    }
}
公共类关闭GracefullyDemo{
私有服务器引导引导;
公共静态void main(字符串[]args)引发异常{
新建ShutdownGracefullyDemo().initialize();
}
private void initialize()引发InterruptedException{
NioEventLoopGroup组=新的NioEventLoopGroup();
bootstrap=newserverbootstrap();
bootstrap.group(组)
.channel(NioServerSocketChannel.class)
.handler(新的LoggingHandler(LogLevel.INFO))
.childHandler(新的MyInboundHandler())
.bind(2025年)
.sync()
.channel()
.closeFuture()
.sync();
}
@ChannelHandler.可共享
私有类MyInboundHandler扩展了SimpleChannelInboundHandler{
Charset Charset=Charset.forName(“US-ASCII”);
@凌驾
受保护的无效channelRead0(ChannelHandlerContext ctx,ByteBuf msg)
抛出异常{
字符串数据=msg.toString(字符集);
系统输出打印项次(“接收:+数据);
如果(“退出”\r\n“.equals(数据)){
关机();
}
}
}
私有无效关闭(){
if(bootstrap!=null&&bootstrap.group()!=null){
bootstrap.group();
系统输出打印项次(“关闭完成”);
}
}
}

您可以使用如下代码关闭:

public void shutdown() {
    LOG.info("Gracefully shutdown http server ...");
    bossGroup.shutdownGracefully(2, 2, TimeUnit.SECONDS);
    workerGroup.shutdownGracefully(2, 2, TimeUnit.SECONDS);
}
类“io.netty.util.concurrent.DefaultPromise”上的方法“SyncUnterruptibly()”源代码:

@覆盖
公共承诺不断地等待着{
if(isDone()){
归还这个;
}
布尔值=假;
已同步(此){
而(!isDone()){
checkDeadLock();
incWaiters();
试一试{
等待();
}捕捉(中断异常e){
//在等待时被打断了。
中断=真;
}最后{
decWaiters();
}
}
}
如果(中断){
Thread.currentThread().interrupt();
}
归还这个;
}

任务在wait()方法上被阻止,它将永远不会继续,直到notify(),所以应用程序无法关闭完成。

问题是您正在创建死锁

您正在从当前事件循环中的某个线程优雅地调用
shutdown
,这将导致该线程计划关闭,然后等待每个线程关闭后再继续。每个线程都不会关闭,因为您正在等待循环关闭,这实际上造成了死锁

在大型应用程序中,有多种方法可以解决此问题:

使用主线程: 这是通过拥有一个调用shutdown方法的全局应用程序主线程来解决的

将侦听器添加到正常关机: 而不是:


因为这允许它从shutdown方法中释放堆栈并正确关闭该线程

感谢Derek的回答!在我的片段中,我从Norman Maurer的书《Netty In action》中获得了灵感,在关机示例中,方法
future.syncunterruptibly()
ShutdownGracely()
之后调用,实际上调用关机并在操作完成时收到通知的underneth逻辑对我来说是有意义的。但由于一些让我困惑的原因,这并没有像预期的那样工作,因为没有人通知等待的线程。也许服务器正在等待所有客户端通道关闭,任务在这个通道上执行,就像死锁一样,所以你可以创建一个新的线程来关闭(或者其他更好的方式)。谢谢@Ferrybig,现在我得到了它。关于你的最后一个建议,关机不应该优雅地关闭所有频道吗?至少在阅读netty的文档时我了解到了这一点:“…它返回一个未来,当EventLoopGroup完全终止并且属于该组的所有通道都已关闭时通知您”@staedler您在最后一点上确实是正确的,netty通过关闭执行者的孩子来关闭频道
@Override
public Promise<V> awaitUninterruptibly() {
    if (isDone()) {
        return this;
    }

    boolean interrupted = false;
    synchronized (this) {
        while (!isDone()) {
            checkDeadLock();
            incWaiters();
            try {
                wait();
            } catch (InterruptedException e) {
                // Interrupted while waiting.
                interrupted = true;
            } finally {
                decWaiters();
            }
        }
    }

    if (interrupted) {
        Thread.currentThread().interrupt();
    }

    return this;
}
.shutdownGracefully().syncUninterruptibly();
System.out.println("shutdown completed");
shutdownGracefully().addListener(e -> {System.out.println("shutdown completed");})