2016-04-11 132 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