2016-04-11 32 views
1

在这段代码中,shutdownGracefully()。syncUninterruptibly()永远不会返回。 这是预期的行为还是我误解了某些东西? 与网状4.0.35.FinalShutdownGracefully()永不返回

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"); 
     } 
    } 
} 

回答

0
可以关闭使用类似下面的代码

测试:

public void shutdown() { 
    LOG.info("Gracefully shutdown http server ..."); 
    bossGroup.shutdownGracefully(2, 2, TimeUnit.SECONDS); 
    workerGroup.shutdownGracefully(2, 2, TimeUnit.SECONDS); 
} 

的方法 “syncUninterruptibly()” 的源代码上的类“io.netty.util.concurrent .DefaultPromise“:

@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; 
} 

任务阻塞在wait()方法,将永远继续下去,直到通知(),所以应用程序不能关闭完成。

+0

谢谢Derek的回答!在我的片段中,我从Norman Maurer的书“Netty in action”中得到了启发,在shutdown例子中,future.syncUninterruptibly()方法在'shutdownGracefully()'之后调用,实际上是调用shutdown的underneth逻辑,操作完成对我有意义。但由于某种原因,让我感到困惑的是,这并不像预期的那样有效,因为没有人通知等待线程。 – staedler

+0

服务器可能正在等待所有客户端通道关闭,并且此任务在此通道上执行,如死锁,因此您可以创建一个关闭的新线程(或其他更好的方法)。 –

1

问题是你正在创建一个死锁。

您正在从当前事件循环中的线程调用shutdownGracefully,这会导致它计划关闭,然后等待直到每个线程都关闭,然后再继续。每个线程都不会关闭,因为您正在等待循环关闭,从而导致死锁。

在一个大的应用程序,有多种方法来解决这个问题:

使用主线程:

这是由具有全球应用的主线程,调用关机方法解决。

添加监听器正常关机:

相反的:

.shutdownGracefully().syncUninterruptibly(); 
System.out.println("shutdown completed"); 

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

由于允许它放松从停止方法堆栈并正确关闭该线程

+0

谢谢@Ferrybig,现在我明白了。关于你最后的建议,不应该shutdownGracefully照顾关闭所有渠道?至少这就是我理解的阅读netty的文档:[link](http://netty.io/wiki/user-guide-for-4.x.html#shutting-down-your-application)“...它返回当EventLoopGroup已完全终止并且属于该组的所有通道都已关闭时,Future会通知您“ – staedler

+0

@staedler对于最后一点,您确实是正确的,netty通过关闭执行程序的子项来关闭通道 – Ferrybig